asp.net-core-webapiodata.net-8.0

Can I put ODataControllers in a subdirectory?


I have an ASP.NET Core 8 Web API project and want to add an ODataController in the Controllers/OData folder. I already have a Controllers/ProjectsController.cs file and want to create a Controllers/OData/ProjectsController.cs file for the ODataController.

However, it's not working. When I call it ODataProjectsController, it works.

I then have the following pieces of code - program.cs:

var modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<ProjectDto>("ODataProjects");

builder.Services.AddControllers().AddOData(
    options => options.Select().Filter().OrderBy().Expand().Count().SetMaxTop(null).AddRouteComponents(
    "odata",
    modelBuilder.GetEdmModel()));

Controllers/OData/ODataProjectsController.cs (using AutoMapper):

public class ODataProjectsController : ODataController
{
    private readonly MyDbContext _db;
    private readonly IMapper _mapper;

    public ODataProjectsController(MyDbContext db, IMapper mapper)
    {
        _db = db;
        _mapper = mapper;
    }

    [HttpGet]
    public async Task<ActionResult> Get(ODataQueryOptions<ProjectDto> options)
    {
        var projects = await _db.ProjectEntities.GetQueryAsync(_mapper, options);
        return Ok(projects);
    }
}

That works great. But when I change my ODataProjectsController to ProjectsController (still in the OData subfolder) and my entity set name to Projects, I get an error:

Endpoint Backend.Api.Controllers.ProjectsController.Get (Backend.Api) contains authorization metadata, but a middleware was not found that supports authorization.

This makes me think ASP.NET Core 8 is confusing the two controllers? Is it even possible to put my OData controllers in a subfolder? I've tried messing about with the ODataRouteComponentAttribute but nothing seemed to work.


Solution

  • Ah, the fix was simple. I was using the wrong attribute. I should use the regular RouteAttribute from ASP.NET Core MVC.

    I also seem to have to name my entityset with lowercase.

    So this is the code that works for me:

    Program.cs:

    var modelBuilder = new ODataConventionModelBuilder();
    modelBuilder.EntitySet<ProjectDto>("projects");
    
    builder.Services.AddControllers().AddOData(
        options => options.Select().Filter().OrderBy().Expand().Count().SetMaxTop(null).AddRouteComponents(
        "odata",
        modelBuilder.GetEdmModel()));
    

    Controllers/OData/ProjectsController.cs:

    [Route("odata/projects")]
    public class ProjectsController : ODataController
    {
        private readonly MyDbContext _db;
        private readonly IMapper _mapper;
    
        public ProjectsController(MyDbContext db, IMapper mapper)
        {
            _db = db;
            _mapper = mapper;
        }
    
        [HttpGet]
        public async Task<ActionResult> Get(ODataQueryOptions<ProjectDto> options)
        {
            var projects = await _db.ProjectEntities.GetQueryAsync(_mapper, options);
            return Ok(projects);
        }
    }