Implementing API versioning in ASP.NET Web API
Microsoft has released a great framework for building (simple) Web API's: ASP.NET Web API. Unfortunately, ASP.NET Web API doesn't support versioning: we cannot say 'this url points to version 1 of the API'. But, fortunately, just like the MVC framework, Web API is very pluggable and this allows us to write our own custom logic. This blog post will show you how to implement versioning in ASP.NET Web API, contains an working example, and source code.
Finding the controllers
In our case, we need to replace the logic that finds and selects the controller to use for an request. In ASP.NET Web API, controller selection is handled by implementations of IHttpControllerSelector. Our task is very simple: implement IHttpControllerSelector. For convenience, I started by copying some of the code of the default ASP.NET Web API IHttpControllerSelector implementation. The source code of ASP.NET Web API is available on Codeplex, so this allows us to easily download and adapt it for our needs.
In our case, we need to replace every logic related to identifying controllers. In the default IHttpControllerSelector implementation, a simple string is used for identifying an controller. For our purposes, this doesn't suffice: we need to identify a controller by both its name and version. The combination of both makes an controller unique for our purpose. For this, I have created an ControllerName helper struct for identifying an controller.
I have called my controller selector implementation 'VersionedControllerSelector'.
Selecting the controller
Returning the controller identifier from the request is actually a small part of the IHttpControllerSelector, the most complicated part is actually finding the controllers and selecting the correct one. Therefore, I have moved the extraction of the controller identity from the request to a seperate class derived from VersionedControllerSelector. The abstract VersionedControllerSelector class only required one method to be implemented: GetControllerName. The GetControllerName has the responsibility for extracting an ControllerName from the HttpRequestMessage specified. The API version selection could be done by routing as the RouteVersionedControllerSelector class does, but selection by HTTP header is of course also possible. Simply derive from the VersionedControllerSelector class and implement the GetControllerName method.
In the case of selecting by route (RouteVersionedControllerSelector), the routing must be modified as the following: api/v{version}/{controller}/{id} instead of api/{controller}/{id}.
Register the new IHttpControllerSelector implementation
If you have set-up ASP.NET web api with an DI/IoC-container such as Autofac or Ninject, you can just register your implementation as a implementation of IHttpControllerSelector. If you do not use an DI container, you can use the following piece of code to register your IHttpControllerSelector implementation:
GlobalConfiguration.Configuration.Services.Replace(typeof (IHttpControllerSelector),
new RouteVersionedControllerSelector(GlobalConfiguration.Configuration));
Working example
Two screenshots are shown below to demonstrate the versioning:


The Source Code
I have put the source code of the project on Github. You can find it in the SDammann.WebApi.Versioning repository. Of course, pull requests and contributions are always welcome.
Nuget package
Starting from version 1.1, a nuget package is also available.
Thanks for reading!
5 Comments
David Price said
Thank you for producing this document, I've used it to great effect.
Do you know if anything in .NET 4.5 has changed the way you would approach this problem?
Also, the caching seemed a little over-kill in your example (made it quite difficult to grasp).
LK said
This article and associated source code needs updating based upon the latest changes in ASP.NET 4.5, especially Web API.
mo said
Ha, I got about half way through writing almost this exact code (sans the caching) before I found this page. Nice one. Using it now :)
Mads Laumann said
Wow, this is JUST what I was looking for!
Thanks a lot! :)
//Mads
Atul said
Hi
Great implementation
I have problem with dynamic route with WEB API Documentation
I am hitting this issue (http://aspnetwebstack.codeplex.com/workitem/865)
Do you have any idea about how to support visioning with API documentation
Thanks-
Atul