2

I am new to OData. I have built an ASP.NET Web API controller as shown below:

using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Web.OData.Routing;

namespace HelloWebApi.Controllers
{
  public class TestsController : ODataController
  {
    ProductsContext db = new ProductsContext();
    private bool TestExists(int key)
    {
      return db.tests.Any(p => p.key== key);
    }
    protected override void Dispose(bool disposing)
    {
      db.Dispose();
      base.Dispose(disposing);
    }

    [EnableQuery]
    public IQueryable<test> Get()
    {
      return db.tests;
    }
  }
}

The model is as shown below:

public class Test
{
  [Key]
  public int key { get; set; }
  public string aaa { get; set; }
}

I have also configured the RouteConfig, ODdataConfig, and WebApiConfig as shown below:

public class RouteConfig
{
  public static void RegisterRoutes(RouteCollection routes)
  {
    routes.Ignore("{resource}.axd/{*pathInfo}");
    routes.MapHttpRoute(
      name: "Default",
      routeTemplate: "{controller}/{action}/{id}"
    );
  }
}

public class ODataConfig
{
  public static void Register(HttpConfiguration config)
  {
    // Web API routes
    config.MapHttpAttributeRoutes();
    ODataModelBuilder builder = new ODataConventionModelBuilder();
    builder.EntitySet<Test>("Tests");
    config.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
  }
}

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    config.Routes.MapHttpRoute(
      name: "DefaultApi",
      routeTemplate: "api/{controller}/{id}",
      defaults: new { id = RouteParameter.Optional }
    );           

  }
}

As well as the global.asax file:

public class WebApiApplication : System.Web.HttpApplication
{
  protected void Application_Start()
  {
    GlobalConfiguration.Configure(config =>
    {
      ODataConfig.Register(config); //this has to be before WebApi
      WebApiConfig.Register(config);
    });
    //FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
  }
}

I tried making a number of modifications in order to resolve this. But I am consistently getting an HTTP 404 Not Found response. I also tried explicitly adding an [ODataRoute] attribute to the action method name; when doing that I instead get an HTTP 406 Not Acceptable response.

The URL I am trying to configure is:

http://localhost:6701/odata/tests/

Where odata is the suffix and tests is the controller name. Please point out what I am doing wrong.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
Jacob Thomas
  • 41
  • 2
  • 6

1 Answers1

5

The routes configured by the ODataConventionModelBuilder are case-sensitive. In your code, you have defined:

builder.EntitySet<Test>("Tests");

Based on this, the endpoint will be:

http://localhost:6701/odata/Tests/

Note the upper-case T in Tests.

This is by design, in order to maintain compatibility with the OData specification.

That said, as of Web API OData 5.4, you can optionally enable case-insensitive routes using the HttpConfiguration class's EnableCaseInsensitive() method. E.g., in your ODataConfig.Register() method you could add:

config.EnableCaseInsensitive(caseInsensitive: true);

For more information, see Basic Case Insensitive Support under Microsoft's ASP.NET Web API for OData V4 Docs.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
  • 1
    Since [Web API OData 5.4](https://www.nuget.org/packages/Microsoft.AspNet.OData/5.4.0), case-insensitive has been supported now. [Here](http://odata.github.io/WebApi/#06-01-custom-url-parsing) is a simple sample page. Thanks. :) – Sam Xu Jun 10 '15 at 08:44
  • Dear Jeremy, Thanks a lot for your suggestion. Now I am able to hit the break point in the controller using the URL you have specified. However, now the response is coming as HTTP 406 not acceptable. – Jacob Thomas Jun 10 '15 at 16:04
  • Hi Sam, Thank you so much for sharing this Url. The case is same (HTTP 406) once when I applied caseInsensitive: true. – Jacob Thomas Jun 10 '15 at 16:14
  • @SamXu I'm embarrassed to have missed that, but really happy to see that it made it into 5.4! A big thanks to you and the OData team for adding that functionality. I've updated my original answer to reflect this. – Jeremy Caney Jun 10 '15 at 16:38
  • @JacobThomas What client are you using? Typically, as you probably know, an HTTP 406 occurs when there's a conflict between the `Accept` header and the content types supported by the server. In the case of Web API OData, that includes `application/json`, `application/atom+xml`, `application/atomsvc+xml`, and `application/xml`. If you're using a web browser to access the server, it should default to `application/xml`, which is typically prioritized in the browser's default `Accept` header. Obviously, if you're programmatically accessing it (e.g., via AJAX), you'll need to set this yourself. – Jeremy Caney Jun 10 '15 at 16:52
  • 1
    @Jeremey & Sam, Infact identified another issue, because of which the 406 error was occured. We need to use "using System.Web.Http.OData;" instead of "using System.Web.OData;". This have resolved my issue. Again thanks a lot for you guys for helping me get this issue resolved. Hurray I implemented Odata :) – Jacob Thomas Jun 10 '15 at 16:54
  • @JacobThomas Aha, good catch! Glad you got that worked out. I don't know if you've had any experience with OData endpoints before, but if not I think you're in for a treat. – Jeremy Caney Jun 10 '15 at 16:58