Search code examples
c#asp.net-coreodata

Microsoft.AspNetCore.OData 8: controller is not found by convention


As described in the docs, Microsoft.AspNetCore.OData 8 uses a convention to tie a controller to an entity set. They also provide a sample that demonstrates this behavior.

However, I've spent several hours to set up a minimal OData API with a simple controller, but the controller is neither shown by the OData routing debug page ($odata) nor can it be accessed through the browser.

This is the model:

namespace TestOData8
{
  public class Dummy
  {
    public int Id { get; set; }
  }
}

This is the controller:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.AspNetCore.OData.Routing.Controllers;

namespace TestOData8.Controllers
{
    public class DummiesController : ODataController
    {
        [HttpGet]
        [EnableQuery]
        public IActionResult Query(CancellationToken ct)
        {
            return Ok(Enumerable.Range(1, 10).Select(x => new Dummy() { Id = x }).AsQueryable());
        }
    }
}

And this code sets up the application (this is the .NET 6 way of setting this up; I've also tried .NET 5 without success):

using Microsoft.AspNetCore.OData;
using Microsoft.OData.Edm;
using Microsoft.OData.ModelBuilder;
using TestOData8;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers()
    .AddOData(opt => opt.Count().Filter().Expand().Select().OrderBy().SetMaxTop(5)
        .AddRouteComponents(GetEdmModel())
    );


IEdmModel GetEdmModel()
{
    var bldr = new ODataConventionModelBuilder();
    bldr.EntitySet<Dummy>("Dummies");
    return bldr.GetEdmModel();
}

var app = builder.Build();

// Configure the HTTP request pipeline.

app.UseHttpsRedirection();

//app.UseAuthorization();

app.UseODataRouteDebug();

app.UseRouting();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

app.Run();

I've asserted that

  • the EDM model is registered (this $metadata endpoint shows the Dummy entity)
  • the name of the controller matches the entity set (Dummies -> DummiesController)
  • routing works for controllers that don't support OData
  • setting the EnableAttributeRouting option to false doesn't change the behavior

What am I missing/misunderstanding?


Solution

  • The fix was very simple: the name of the method in the controller must be "Get"; after changing the action name, the controller worked:

    public class DummiesController : ODataController
    {
        [HttpGet]
        [EnableQuery]
        public IActionResult Get(CancellationToken ct)
        {
            return Ok(Enumerable.Range(1, 10).Select(x => new Dummy() { Id = x }).AsQueryable());
        }
    }
    

    Thanks to @JamesLove for a small comment under another answer.