Search code examples
c#asp.net-web-apiodata

OData routes return 404 Not Found


I've started including OData in my WebAPi2 project (currently hosted in IIS8 Express on my dev machine). My OData config class looks like this:

public class ODataConfig
{
    private readonly ODataConventionModelBuilder modelBuilder;

    public ODataConfig()
    {
        modelBuilder = new ODataConventionModelBuilder();

        modelBuilder.EntitySet<Category>("Category");
    }

    public IEdmModel GetEdmModel()
    {
        return modelBuilder.GetEdmModel();
    }
}

Then I added the following in my WebApiConfig class:

ODataConfig odataConfig = new ODataConfig();

config.MapODataServiceRoute(
    routeName: "ODataRoute",
    routePrefix: "MyServer/OData",
    model: odataConfig.GetEdmModel(),
    defaultHandler: sessionHandler
);

And started with a basic controller and just one action, like this:

public class CategoryController : ODataController
{
    [HttpGet]
    public IHttpActionResult Get([FromODataUri] int key)
    {
        var entity = categoryService.Get(key);
        if (entity == null)
            return NotFound();

        return Ok(entity);
    }
}

Then, in my HttpClient, the request url looks like this: MyServer/OData/Category(10)

However, I'm getting the following error:

{"Message":"No HTTP resource was found that matches the request URI 'http://localhost/MyServer/OData/Category(10)'.","MessageDetail":"No type was found that matches the controller named 'OData'."}

What am I missing here?

EDIT

If I set the routePrefix to null or 'odata' and change my request url accordingly, the request works fine. So this means that I can't have a route prefix like 'myServer/odata'.

Is this OData standard naming convention? And if yes, can it be overridden?


Solution

  • I've been using the same WebApiConfig.Register() method that is included by default in the Web API project and passing using the following:

    var builder = new ODataConventionModelBuilder();
    
    // OData entity sets..
    builder.EntitySet<Seat>("Seats");
    builder.EntitySet<Table>("Tables");
    
    // Configure the Route
    config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
    

    The first parameter is a friendly name, the second is the one you're after! You can change this to whatever you want.

    UPDATE: If you're using OData V4, the routing is initialised like this:

    config.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());

    If you're using V4, method based routing via the use of attributes is now available (think Nancy style)

    You can use this in either an OWIN startup class or the Global.asax. Either way works fine for me.

    Refer: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v3/creating-an-odata-endpoint