Take advantage of the various ways to version your Web API to make it more flexible and adaptable to changes while keeping the functionality intact Credit: Matejmo / Getty Images You should always version your Web API while at the same time keeping as much of the same URI as possible. Imagine a situation where you have a Web API that is up and running in production and is being consumed by users. Now suppose you need more functionality in the Web API yet must keep the existing functionality intact. You may have a few users who still need the old API, while others will need a version with new or extended features. This is exactly where Web API versioning comes to the rescue. You can version your Web API in one of the following ways: Use URLs: Version information is specified in the URL as a query string. Use Custom Request Headers: Version information for your controller is specified in the request header sans the need for any changes in the URL. Use Accept Headers: Accept headers generally define the media type and character encodings. You can pass version information for your Web API via accept headers without having to change the URL. Versioning Web API using URLs Consider the following Web API controllers, which have been named AuthorsV1Controller and AuthorsV2Controller respectively. public class AuthorsV1Controller : ApiController { [HttpGet] public IEnumerable<string> GetAuthors() { return new string[] { "Joydip Kanjilal", "Gerben Wierda" }; } } public class AuthorsV2Controller : ApiController { [HttpGet] public IEnumerable<string> GetAuthors() { return new string[] { "Joydip Kanjilal, INDIA", "Gerben Wierda, Netherlands" }; } } To simplify this illustration, I’ve incorporated a method named GetAuthors() in each controller. While GetAuthors() in AuthorsV1Controller returns only the author names, GetAuthors() in AuthorsV2Controller (the new version) returns the author names along with the names of the countries in which the authors reside. The following code snippet shows how the two controllers use the Register method of the WebApiConfig class. config.Routes.MapHttpRoute( name: "IDGWebAPIV1", routeTemplate: "api/v1/{controller}/{id}", defaults: new { controller= "AuthorsV1Controller", action="GetAuthors", id = RouteParameter.Optional } ); config.Routes.MapHttpRoute( name: "IDGWebAPIV2", routeTemplate: "api/v2/{controller}/{id}", defaults: new { controller = "AuthorsV2Controller", action = "GetAuthors", id = RouteParameter.Optional } ); You can now invoke the Web API method GetAuthors using the following URL. http://localhost/IDGWebAPI/api/v1/Authors/GetAuthors Versioning Web API using the request header You can also implement Web API versioning using the request header. To achieve this, you need to implement a custom class that extends the DefaultHttpControllerSelector class, then override SelectController in your custom class. Note that the DefaultHttpControllerSelector class implements the IHttpControllerSelector interface. SelectController calls GetControllerName internally and accepts an instance of HttpRequestMessage as a parameter. The following code snippet illustrates how you can retrieve version information from the request header. private string GetControllerVersionFromRequestHeader(HttpRequestMessage request) { var acceptHeader = request.Headers.Accept; const string headerName = "Version"; string controllerVersion = string.Empty; if (request.Headers.Contains(headerName)) { controllerVersion = "V"+request.Headers.GetValues(headerName).First(); } return controllerVersion; } Versioning Web API using the accept header The following method shows how you can retrieve version information for your Web API from the accept header. The method checks the MIME type and returns the version information appropriately. If the media type is not application/json, the default version is returned as V1. private string GetControllerVersionFromAcceptHeader(HttpRequestMessage request) { var acceptHeader = request.Headers.Accept; string controllerVersion = string.Empty; foreach (var mime in acceptHeader) { if (mime.MediaType.Equals("application/json")) { NameValueHeaderValue version = mime.Parameters.FirstOrDefault(v => v.Name.Equals("Version", StringComparison.OrdinalIgnoreCase)); controllerVersion = "V" + version.Value.ToString(); return controllerVersion; } } return "V1"; } You can invoke your Web API from Fiddler by passing the accept header as shown below. Accept: application/json; charset=utf-8;version=2 The following code listing illustrates how you can override SelectController to select a controller dynamically. Note how GetControllerVersionFromRequestHeader has been used. If you would like to retrieve the controller version from the accept header, you should leverage GetControllerVersionFromAcceptHeader instead. public override HttpControllerDescriptor SelectController(HttpRequestMessage request) { try { string controllerName = base.GetControllerName(request); var controllers = GetControllerMapping(); var routeData = request.GetRouteData(); string controllerVersion = GetControllerVersionFromRequestHeader(request); controllerName = String.Format("{0}{1}", controllerName, controllerVersion); HttpControllerDescriptor controllerDescriptor; if (!controllers.TryGetValue(controllerName, out controllerDescriptor)) { string message = "No HTTP resource was found that matches the specified request URI {0}"; throw new HttpResponseException(request.CreateErrorResponse(System.Net.HttpStatusCode.NotFound, String.Format(message, request.RequestUri))); } return controllerDescriptor; } catch (Exception ex) { throw new HttpResponseException(request.CreateErrorResponse(System.Net.HttpStatusCode.NotFound, String.Format(ex.Message, request.RequestUri))); } } You should add the following line in the Register method of the WebApiConfig class to provide support for controller selection at runtime. config.Services.Replace(typeof(IHttpControllerSelector), new IDGControllerSelector((config))); You can now use Fiddler to test your Web API — use the composer tab of Fiddler and provide the URL and version information as appropriate. If you want version 2 of your Web API controller to be invoked, you should specify Version: 2 when composing the request header information in the Composer tab in Fiddler. Related content how-to How to use FastEndpoints in ASP.NET Core Take advantage of the free open-source FastEndpoints library to build fast and lean APIs in your ASP.NET Core applications. By Joydip Kanjilal Jul 11, 2024 7 mins Microsoft .NET C# Development Libraries and Frameworks how-to How to use Refit to consume APIs in ASP.NET Core Take advantage of Refit REST library to simplify API consumption and make your code cleaner, more efficient, and easier to maintain. By Joydip Kanjilal Jul 04, 2024 10 mins C# Microsoft .NET Software Deployment how-to When to use an abstract class vs. interface in C# Understanding the differences between an abstract class and interface is key to designing loosely coupled and extensible applications. By Joydip Kanjilal Jun 20, 2024 10 mins Small and Medium Business Microsoft .NET C# how-to 6 security best practices for ASP.NET Core Learn the best practices and built-in safeguards for preventing attacks and protecting sensitive data in your ASP.NET Core web applications. By Joydip Kanjilal Jun 07, 2024 6 mins C# Microsoft .NET Web Development Resources Videos