Search code examples
.net-coreodataasp.net-core-webapi.net-6.0

Set custom route using OData 8


Recently I updated to OData 8.0.10. I added this in my Startup.cs file:

services.AddRouting();
services.AddControllers().AddOData(opt => 
opt.AddRouteComponents("odata", GetEdmModel()).Filter().Select().OrderBy().Count());

where

private static IEdmModel GetEdmModel()
{
    ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
    builder.EntitySet<Project>("Project");
    return builder.GetEdmModel();
}

I have this small controller

[Route("api/[controller]")]
[ApiController]
public class ProjectController : ControllerBase
{
    [HttpGet]
    [EnableQuery(PageSize = 20)]
    public IQueryable<Project> GetAsync()
    {
        var projects = _projectRepository.GetAll();
        return projects;
    }

    [HttpGet("{id}", Name = "GetProjectById")]
    public async Task<ActionResult> GetAsyncById(long id)
    {
        var project = await _projectService.GetProjectByIDAsync(id);
        return Ok(project);
    }

    [HttpPatch("{id}", Name = "PatchProjectById")]
    public async Task<ActionResult> PatchProject(long id, [FromBody] ProjectPatchDetails projectPatch)
    {
        var project = await _projectRepository.GetAsync(id);
        var updated = await _projectService.UpdateProjectAsync(id, project, projectPatch);
        return Ok(updated);
    }
}

that has three endpoints, one of them is annotated by [EnableQuery] and the rest aren't. When I access api/project?$count=true&$skip=0&$orderby=CreateDate%20desc, I get a paged info (20 records) but I don't get the @odata.context and @odata.count. If I access /odata/project?$count=true&$skip=0&$orderby=CreateDate%20desc, with odata/ prefix, it gives me @odata.context and @odata.count. I tried changing AddRouteComponents to AddRouteComponents("api", GetEdmModel()) but in this case I get the following error:

"The request matched multiple endpoints. Matches: MyApp.Api.Controllers.ProjectController.GetAsync (MyApp.Api) MyApp.Api.Controllers.ProjectController.GetAsync (MyApp.Api)"

I have multiple questions in this case:

  1. Is there a way to reroute odata to api, make /odata prefix as /api and make it work?
  2. Should I make another controller that will store all OData tagged actions and on this way maybe workaround this as a solution, if possible?

Solution

  • @anthino

    1. Is there a way to reroute odata to api, make /odata prefix as /api and make it work?

    if you add 'opt.AddRouteComponents("api", GetEdmModel())', remember to remove [Route("api/[controller]")] and other attribute routings

    1. Should I make another controller that will store all OData tagged actions and on this way maybe workaround this as a solution, if possible?

    Basically, it's better to create two controllers, one for odata, the other for others. In your scenario, you mixed them together. You should be careful about this. You can use 'app.UseODataRouteDebug()' middleware to help you debug.