ASP.NET Core API Versioning In Simple Words (Update 1.2.0)

This article shows you how to enable API versioning for ASP.NET Core Web API following the three different techniques.

A few days ago, my friends and I developed an API using ASP.NET Core where from the GET method, we returned some data to our client app. We did pagination in the front end. This means that first we sent all the data to the client and then did some data length operation on that to get the item count for applying pagination logic. Then, we decided that we should do the logic in the back-end (server-side pagination) because it will decrease the payload of the HTTP request. In our case, it wasn’t any problem since we had total control over our client app (it’s singular). We changed all the logic  both in the client and server for that. And we were fine with it.

However, there is a possibility that you will have additional clients and only a single source of truth (API). Introducing a breaking change in one API can support one client meanwhile breaking others. For example, let’s say your mobile team is on vacation and your web team is working hard on that server-side pagination. To support the web team, you made a simple change (who cares!) in the API. You and your web team are happy (if you are happy and you know it, clap your hands) with that change. The nightmares begin when you find out that your million-dollar mobile client is not working for that very simple (yet breaking) change and people are uninstalling it. More nightmares come later when you find out that you are neither a mobile app developer nor do you have access to its source code. Now you only have the option of downgrading both your API and web app. But the team who made the web app are now on vacation too. I’ll stop there now because there are too many nightmares going around here.

Maybe (not maybe. It is!) API versioning is a good practice in that case. With API versioning, you can not only be safe from those breaking changes but can also support those. It’s a win-win situation for everyone.

Let’s see how to configure API versioning in ASP.NET Core.

Note

I’m using an empty ASP.NET Core Web API project (.NET Core 1.1)

Install this package via NuGet - Microsoft.AspNetCore.Mvc.Versioning. Now, configure it as a service (i.e., services.AddApiVersioning()) in the ConfigureServices() method of Startup.cs (duh! Like I didn’t know that was coming)

  1. public void ConfigureServices(IServiceCollection services)  
  2. {  
  3.     services.AddMvc();  
  4.     services.AddApiVersioning();  
  5. }  

Following app.UseApiVersioning() middleware configuration is only needed when you are using version 1.1.1 of Microsoft.AspNetCore.Mvc.Versioning.

  1. public void Configure(IApplicationBuilder app, IHostingEnvironment env,   
  2.                       ILoggerFactory loggerFactory)  
  3. {  
  4.     /* garbage code removed */  
  5.     app.UseMvc();  
  6.     app.UseApiVersioning();  
  7. }  

Next, you have to decorate (i.e., ApiVersion) the controller on which you want support for API versioning (multiple versions). Likewise, you would also have to decorate (i.e., MapToApiVersion) your actions with a specific API version number

  1. [ApiVersion("1.0")]  
  2. [Route("api/[controller]")]  
  3. public class ValuesController : Controller  
  4. {  
  5.     // GET api/values  
  6.     [MapToApiVersion("1.0")]  
  7.     [HttpGet]  
  8.     public IEnumerable<string> Get()  
  9.     {  
  10.         return Json(new string[] { "value1""value2" });  
  11.     }  
  12. }  

Now, to get the GET action result, you have to specify the API version (which it responds to) of it. For the time being, use the query string versioning way. In this way, you will specify the API version directly in the query string. Like this: http://localhost:5000/api/values?api-version=1.0

If you are adding API versioning to your existing API project, you can tell ASP.NET Core to treat the undercoated controllers and actions to have version 1.0 by default. To do that, configure the AddApiVersioning() service like below,

  1. services.AddApiVersioning(options => options.AssumeDefaultVersionWhenUnspecified = true);  

You can now make a call to the API like http://localhost:5000/api/values with no harms made.

In the above configuration (default to version 1.0), note that you will have to explicitly define the ApiVersion("1.0") when you want to use other versions along with it. However, you don’t have to decorate the action in this case. Below is an example of the situation

  1. [ApiVersion("2.0")]  
  2. [Route("api/[controller]")]  
  3. public class ValuesController : Controller  
  4. {  
  5.     [HttpGet]  
  6.     public IActionResult Get()  
  7.     {  
  8.         return Json(new string[] { "value1""value2" });  
  9.     }  
  10.   
  11.     [HttpGet, MapToApiVersion("2.0")]  
  12.     public IActionResult GetWithTotal()  
  13.     {  
  14.         var data = new string[] { "value1""value2" };  
  15.         var total = data.Length;  
  16.         return Json(new { data = data, total = total });  
  17.     }  
  18. }  

There are three ways in which you can specify the API version. They can be set via

  • Querystring (already discussed)
  • URL Path Segment
  • Media types

In URL Path Versioning way, you pass the version number as a segment of your URL path. Like this for example, http://localhost:5000/api/v1/values. By the way, you have to modify your Route attribute to accommodate version segment in it like below

  1. [ApiVersion("1.0")]  
  2. [Route("api/v{version:apiVersion}/[controller]")]  
  3. public class ValuesController : Controller  
  4. {  
  5.     [HttpGet, MapToApiVersion("1.0")]  
  6.     public IActionResult Get()  
  7.     {  
  8.         return Json(new string[] { "value1""value2" });  
  9.     }  
  10. }  

Note that the letter v is not mandatory to add in front of the version number. It’s just a convention.

Last of all, you can configure your service to read the API version number from a specific Media Type (By default, it reads from the content-type media type by default. you can configure your own media type). Configure your service like the below to activate media type visioning,

  1. public void ConfigureServices(IServiceCollection services)  
  2. {  
  3.         // Add framework services.  
  4.     services.AddMvc();  
  5.     services.AddApiVersioning(options =>  
  6.     {  
  7.         options.ApiVersionReader = new MediaTypeApiVersionReader();  
  8.         options.AssumeDefaultVersionWhenUnspecified = true;  
  9.         options.ApiVersionSelector = new CurrentImplementationApiVersionSelector(options);  
  10.     });  
  11. }  

Now, when you make an HTTP request, specify the API version as a part of the content-type media type in the header section like below (content-type: application/json;v=2.0).

ASP.NET Core

By the way, the CurrentImplementationApiVersionSelector option will take the most recent API version if there is no version defined as a part of the content-type media type. In the following example, I didn’t mention any version number so it’s taking the most recent version among all the versions.

ASP.NET Core

And that's not all. There are other cool features available and you can find those here in Microsoft's ASP.NET API Versioning Git repository,
  • https://github.com/Microsoft/aspnet-api-versioning/wiki