I don't understand all the concepts behind this and I believe most of us don't, and don't care to. Still, feel free to explain the unexplained in the comments.
So, I started with a ASP.Net Application project. I Selected Web API for the template so I could have the help pages ready. Then I added the needed stuff for OData V4 following this really nice tutorial. Last, I had to configure the ROUTES, and that is where all hell resides (well, that's what all the blog posts and obscure SO questions lead me to think). THe following has been taken from my SO answer.
The order in which the routes are configured has an impact. In my case, I also have some standard MVC controllers and help pages.
Global.asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(config =>
{
ODataConfig.Register(config); //this has to be before WebApi
WebApiConfig.Register(config);
}); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); }
The filter and routeTable parts weren't there when I started my project and are needed.
ODataConfig.cs:
public static void Register(HttpConfiguration config) { config.MapHttpAttributeRoutes(); //This has to be called before the following OData mapping, so also before WebApi mapping ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.EntitySet("Sites"); //Moar! config.MapODataServiceRoute("ODataRoute", "api", builder.GetEdmModel()); }
WebApiConfig.cs:
public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( //MapHTTPRoute for controllers inheriting ApiController name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); }
RouteConfig.cs:
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( //MapRoute for controllers inheriting from standard Controller name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); }
This has to be in that EXACT ORDER. I tried moving the calls around and ended up with either MVC, Api or Odata broken with 404 or 406 errors.
So I can call:
localhost:xxx/ -> leads to help pages (home controller, index page)
localhost:xxx/api/ -> leads to the OData $metadata
localhost:xxx/api/Sites -> leads to the Get method of my SitesController inheriting from ODataController
localhost:xxx/api/Test -> leads to the Get method of my TestController inheriting from ApiController.