Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

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

0.00/5 (No votes)
20 Jul 2017 1  
This article shows you how to enable API versioning for ASP.NET Core Web API following three different techniques.

Few days ago, me and my friends 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. Means that first we sent all the data to the client and then did some data.length operation on that to get the items 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 an extreme control over our client app (it’s singular). We changed all the logic here and there 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 their asses off for that server-side pagination stuff. To support the web team, you made a simple change (who cares!) in the API. You and your web team both 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 neither are you 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 cause 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 against 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):

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddApiVersioning();
}

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

public void Configure(IApplicationBuilder app, IHostingEnvironment env, 
                      ILoggerFactory loggerFactory)
{
    /* garbage code removed */
    app.UseMvc();
    app.UseApiVersioning();
}

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:

[ApiVersion("1.0")]
[Route("api/[controller]")]
public class ValuesController : Controller
{
    // GET api/values
    [MapToApiVersion("1.0")]
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return Json(new string[] { "value1", "value2" });
    }
}

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:

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:

[ApiVersion("2.0")]
[Route("api/[controller]")]
public class ValuesController : Controller
{
    [HttpGet]
    public IActionResult Get()
    {
        return Json(new string[] { "value1", "value2" });
    }

    [HttpGet, MapToApiVersion("2.0")]
    public IActionResult GetWithTotal()
    {
        var data = new string[] { "value1", "value2" };
        var total = data.Length;
        return Json(new { data = data, total = total });
    }
}

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:

[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class ValuesController : Controller
{
    [HttpGet, MapToApiVersion("1.0")]
    public IActionResult Get()
    {
        return Json(new string[] { "value1", "value2" });
    }
}

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:

public void ConfigureServices(IServiceCollection services)
{
        // Add framework services.
    services.AddMvc();
    services.AddApiVersioning(options =>
    {
        options.ApiVersionReader = new MediaTypeApiVersionReader();
        options.AssumeDefaultVersionWhenUnspecified = true;
        options.ApiVersionSelector = new CurrentImplementationApiVersionSelector(options);
    });
}

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):

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.

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:

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here