Search code examples
asp.net-web-apiodata

ASP.NET WebAPI: Generic controller for OData endpoint


I'm currently experimenting with OData endpoints in ASP.NET MVC 4 Web API. I like the concept and try to come up with efficient ways to use it in our project. One question I have is the following: we have a service that is able to return an IQueryable and takes the name of an entity as Input:

public IQueryable GetAll(string entityName);

In standard Web API (as opposed to OData Controllers) I can create a generic controller, that can be called in the form /api/entities/{entityName} and returns the IQueryable. In case of an OData Controller, I carry out the following entity-specific steps:

  1. Register the entities in the model.
  2. Create a separate Controller for each entity that derives from EntitySetController<>.

I want to use the generic service and avoid as much entity-specific implementations as possible. The first step can easily be automated if the service can return a list of the entities and the corresponding types. That leaves step 2, because up to now I need to create a specific controller for each entity. I also want to avoid that and create a generic controller that uses the generic service.

Can anyone recommend a solution, maybe by influencing OData routing?


Solution

  • You can create a custom routing convention that selects the same controller no matter what the entity set is. Example,

    public class CustomControllerRoutingConvention : IODataRoutingConvention
    {
        public string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, ILookup<string, HttpActionDescriptor> actionMap)
        {
            return null;
        }
    
        public string SelectController(ODataPath odataPath, HttpRequestMessage request)
        {
            return "SomeFixedContrllerNameWithoutTheControllerSuffix";
        }
    }
    

    You can register that routing convention using the following code,

    IList<IODataRoutingConvention> routingConventions = ODataRoutingConventions.CreateDefault();
    routingConventions.Insert(0, new CustomControllerRoutingConvention());
    config.Routes.MapODataRoute("OData", "odata", builder.GetEdmModel(), new DefaultODataPathHandler(), routingConventions);