Web
API Versioning is required as the business grows and business
requirement changes with the time. As Web API can be consumed by
multiple clients at a time, Versioning of Web API will be necessarily
required so that Business changes in the API will not impact the client
that are using/consuming the existing API.
For Demonstration, we have two controller EmployeeV1 and EmployeeV2. Both will return different data as EmployeeV1 return employees details with ID, Name, Age, City, State property and EmployeeV2 returns employees with ID, FirstName, LastName (In V1, we have name property), DOB (In V1 we have Age property), City, State, Country etc. property.
Now open WebApiConfig.cs file and configure the route as mentioned in below image.
In the above image, we have configured the route so that if Web API
receives an HTTP request, it tries to match with the one of the routes
in the routing table and call the mapped API controller. Let’s try to
hit the API with the Postman.
In the above image, we hit the Web API with the configured V1 route.
As we already specified in the route, “/api/v1/employee” will call the
EmployeeV1Controller. Now, let's call the V2 API with the Postman. In
the below image, we can clearly see that we are able to call
EmployeeV2Controller without any issue.
We can also use attribute-based routing for URI based API Versioning.
Code Snippet
Now, let’s hit the API and fetch the data from the version 1 i.e. EmployeeV1Controller using Postman.
And get data from EmployeeV2Controller with as version=2 as a query
string parameter and an id to fetch the value of particular employees.
Code Snippet
But in case user pass same headers multiple times,
request.Headers.GetValues(customHeaderForVersion).FirstOrDefault() will
return multiple values separated by comma. Let’s try the same scenario
with Postman. Add the break point In the CustomSelectorController.cs so
that It can be analyzed on hitting the send button from the Postman.
You will see comma separated as same Custom header is passed multiple times.
In order to fix that, first check that apiVersion variable contains a
comma. If true, then pick the first value separated by the comma from
the headers.
Pass the accept header using the postman in order to test the API Versioning.
Web API Versioning Ways
Web API Versioning can be done by using the following methods:- URI
- QueryString parameter
- Custom Header parameter
- Accept Header parameter
Web API Versioning using URI
In this method, Web API URI is changed with the help of routing and is more readable. Let’s say, we have an existing running API in which one URI returns some response. All Clients are consuming the same API and one client wants some changes by requesting to add new properties. With Versioning, we can achieve the same without breaking the existing API flow. In this case, Web API Versioning using URI is one of the best ways to achieve the same.For Demonstration, we have two controller EmployeeV1 and EmployeeV2. Both will return different data as EmployeeV1 return employees details with ID, Name, Age, City, State property and EmployeeV2 returns employees with ID, FirstName, LastName (In V1, we have name property), DOB (In V1 we have Age property), City, State, Country etc. property.
Image: EmployeeV2Controller
Image: WebApiConfig.cs
Image: Hitting the V1 API with the Postman
Image: Hitting the V2 API with the Postman
Image: Attribute based routing in Web API
Web API Versioning using QueryString parameter
In Web API Versioning using Query String, a query string parameter is added to the query string in order to find the controller or Action to which request is sent. Whenever a request comes, SelectController() method of DefaultHttpControllerSelector Class selects the controller information from the information passed in the URI. In order to achieve the versioning with Query String, we need to create a Custom DefaultHttpControllerSelector and override the SelectController() method.Code Snippet
Before running the API, remove the routing attribute added in the Web API Versioning using URI. Replace the IHttpControllerSelector with CustomSelectorController in WebApiConfig.cs file.
- public class CustomSelectorController : DefaultHttpControllerSelector
- {
- HttpConfiguration _config;
- public CustomSelectorController(HttpConfiguration config):base(config) {
- _config = config;
- }
- public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
- {
- //returns all possible API Controllers
- var controllers = GetControllerMapping();
- //return the information about the route
- var routeData = request.GetRouteData();
- //get the controller name passed
- var controllerName = routeData.Values["controller"].ToString();
- string apiVersion = "1";
- //get querystring from the URI
- var versionQueryString = HttpUtility.ParseQueryString(request.RequestUri.Query);
- if (versionQueryString["version"]!=null)
- {
- apiVersion = Convert.ToString(versionQueryString["version"]);
- }
- if (apiVersion=="1") {
- controllerName = controllerName + "V1";
- }
- else
- {
- controllerName = controllerName + "V2";
- }
- //
- HttpControllerDescriptor controllerDescriptor;
- //check the value in controllers dictionary. TryGetValue is an efficient way to check the value existence
- if (controllers.TryGetValue(controllerName,out controllerDescriptor)) {
- return controllerDescriptor;
- }
- return null;
- }
- }

Image: Replace IHttpControllerSelector with CustomSelectorController
Image: Fetch Data using Query string i.e. from EmployeeV1Controller
Image: using Query string i.e. from EmployeeV2Controller with id=2
Web API Versioning using Custom Header parameter
Custom Headers are used for providing additional information, troubleshooting and implementing server-side logic, etc. We will send the version information in the custom header and check the its value and return the response according to its value.Code Snippet
Now, hit the API using Postman with the custom headers mentioned in the code.
- //Web API Versioning using Custom Headers
- public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
- {
- //returns all possible API Controllers
- var controllers = GetControllerMapping();
- //return the information about the route
- var routeData = request.GetRouteData();
- //get the controller name passed
- var controllerName = routeData.Values["controller"].ToString();
- string apiVersion = "1";
- //Custom Header Name to be check
- string customHeaderForVersion = "X-Employee-Version";
- if (request.Headers.Contains(customHeaderForVersion)) {
- apiVersion=request.Headers.GetValues(customHeaderForVersion).FirstOrDefault();
- }
- if (apiVersion == "1")
- {
- controllerName = controllerName + "V1";
- }
- else
- {
- controllerName = controllerName + "V2";
- }
- //
- HttpControllerDescriptor controllerDescriptor;
- //check the value in controllers dictionary. TryGetValue is an efficient way to check the value existence
- if (controllers.TryGetValue(controllerName, out controllerDescriptor))
- {
- return controllerDescriptor;
- }
- return null;
- }
Image: Custom Header for API Versioning
Image: Same Custom Header added multiple times
Image: Comma Separated custom header values
Web API Versioning using Accept Header parameter
Accepts Headers requests the server about the file format of the data required by the browser. This data is expressed as MIME Types which stands for “Multipurpose Internet Mail Exchange”. The MIME type is generally case-insensitive, but traditionally written in small letters. We need to make small changes in the above code in order to accept the version parameter value from the accept header.Image: Get request with Accept Parameter using Postman