Inheriting route attributes in ASP.NET Web API

I was recently working on a project, where I had a need to inherit routes from a generic base Web API controller. This is not supported by Web API out of the box, but can be enabled with a tiny configuration tweak. Let’s have a look.

The problem with inheriting attribute routes

If you look at the definition of the RouteAttribute in ASP.NET Web API, you will see that it’s marked as an “inheritable” attribute. As such, it’s reasonable to assume that if you use that attribute on a base controller, it will be respected in a child controller you create off the base one.

However, in reality, that is not the case, and that’s due to the internal logic in DefaultDirectRouteProvider – which is the default implementation of the way how Web API discovers attribute routes.

We discussed this class (and the entire extensibility point, as the direct route provider can be replaced) before – for example when implementing a centralized route prefix for Web API.

So if this is your generic Web API code, it will not work out of the box:

Ignoring the implementation details of the repository pattern here, assuming all your dependency injection is configured already – with the above controller, trying to hit api/items/{id} is going to produce 404.

The solution for inheriting attribute routes

One of the methods that this default direct route provider exposes as overrideable, is the one shown below. It is responsible for extracting route attributes from an action descriptor:

Without going into too much details about this code – it’s clearly visible that it specifically ignores inherited route attributes (route attributes implement IDirectRouteFactory interface).

So in order to make our initial sample generic controller work, we need to override the above method and read all inherited routes. This is extremely simple and is shown below:

This can now be registered at the application startup against your HttpConfiguration – which is shown in the next snippet as an extension method + OWIN Startup class.

And that’s it!