How to use API versioning in ASP.NET Core

Take advantage of API versioning in ASP.NET Core to manage the impact of changes to your APIs on your clients

How to use API versioning in ASP.NET Core
robynmac / Getty Images

When developing APIs, you should keep one thing in mind: Change is inevitable. When your API has reached a point where you need to add more responsibilities, you should consider versioning your API. Hence you will need a versioning strategy.

There are several approaches to versioning APIs, and each of them has its pros and cons. This article will discuss the challenges of API versioning and how you can work with Microsoft’s ASP.NET Core MVC Versioning package to version RESTful APIs built in ASP.NET Core. You can read more about Web API versioning in my previous article here

Create an ASP.NET Core 3.1 API project

First off, let’s create an ASP.NET Core project in Visual Studio. Assuming Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new ASP.NET Core project in Visual Studio.

  1. Launch the Visual Studio IDE.
  2. Click on “Create new project.”
  3. In the “Create new project” window, select “ASP.NET Core Web Application” from the list of templates displayed.
  4. Click Next.
  5. In the “Configure your new project” window shown next, specify the name and location for the new project.
  6. Click Create.
  7. In the “Create New ASP.NET Core Web Application” window, select .NET Core as the runtime and ASP.NET Core 3.1 (or later) from the drop-down list at the top. I’ll be using ASP.NET Core 3.1 here.
  8. Select “API” as the project template to create a new ASP.NET Core API application. 
  9. Ensure that the check boxes “Enable Docker Support” and “Configure for HTTPS” are unchecked as we won’t be using those features here.
  10. Ensure that Authentication is set as “No Authentication” as we won’t be using authentication either.
  11. Click Create. 

This will create a new ASP.NET Core API project in Visual Studio. Select the Controllers solution folder in the Solution Explorer window and click “Add -> Controller…” to create a new controller named DefaultController.

Replace the source code of the DefaultController class with the following code.

    [Route("api/[controller]")]
    [ApiController]
    public class DefaultController : ControllerBase
    {
        string[] authors = new string[]
        { "Joydip Kanjilal", "Steve Smith", "Stephen Jones" };
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return authors;
        }
    }

We’ll use this controller in the subsequent sections of this article.

To implement API versioning in ASP.NET Core you need to do the following:

  1. Install the ASP.NET Core MVC Versioning package.
  2. Configure API versioning in the Startup class.
  3. Annotate the controllers and actions with appropriate attributes.

Install the ASP.NET Core MVC Versioning package

ASP.NET Core provides support for API versioning out-of-the-box. To leverage API versioning, all you need to do is install the Microsoft.AspNetCore.Mvc.Versioning package from NuGet. You can do this either via the NuGet package manager inside the Visual Studio 2019 IDE, or by executing the following command at the NuGet package manager console:

Install-Package Microsoft.AspNetCore.Mvc.Versioning

Note that if you’re using ASP.NET Web API, you should add the Microsoft.AspNet.WebApi.Versioning package.

Configure API versioning in ASP.NET Core

Now that the necessary package for versioning your API has been installed in your project, you can configure API versioning in the ConfigureServices method of the Startup class. The following code snippet illustrates how this can be achieved.

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

When you make a Get request to your API, you will be presented with the error shown in Figure 1.

api versioning 01 IDG

Figure 1

To solve this error, you can specify the default version when adding the API versioning services to the container. You might also want to use a default version if a version is not specified in the request. The following code snippet shows how you can set a default version as 1.0 using the AssumeDefaultVersionWhenUnspecified property if version information isn’t available in the request.

services.AddApiVersioning(config =>
{
   config.DefaultApiVersion = new ApiVersion(1, 0);
   config.AssumeDefaultVersionWhenUnspecified = true;
});

Note how the major version and minor version are passed to the constructor of the ApiVersion class at the time of assigning the default version. The property AssumeDefaultVersionWhenUnspecified can hold either true or false values. If it is true, the default version specified when configuring API versioning will be used if no version information is available.

The complete source code of the ConfigureServices method is given below for your reference.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddApiVersioning(config =>
    {
         config.DefaultApiVersion = new ApiVersion(1, 0);
         config.AssumeDefaultVersionWhenUnspecified = true;
    });
}

Since you haven’t specified any version information, all endpoints will have the default version 1.0.

Report all supported versions of your API

You might want to let the clients of the API know all supported versions. To do this, you should take advantage of the ReportApiVersions property as shown in the code snippet given below.

services.AddApiVersioning(config =>
{
  config.DefaultApiVersion = new ApiVersion(1, 0);
  config.AssumeDefaultVersionWhenUnspecified = true;
  config.ReportApiVersions = true;
});

Use versions in the controller and action methods

Now let’s add a few supported versions to our controller using attributes as shown in the code snippet given below.

    [Route("api/[controller]")]
    [ApiController]
    [ApiVersion("1.0")]
    [ApiVersion("1.1")]
    [ApiVersion("2.0")]
    public class DefaultController : ControllerBase
    {
        string[] authors = new string[]
        { "Joydip Kanjilal", "Steve Smith", "Anand John" };
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return authors;
        }
    }

When you make a Get request from an HTTP client such as Postman, here’s how the versions will be reported.

api versioning 02 IDG

Figure 2

You can report the deprecated versions as well. To do this, you should pass an extra parameter to the ApiVersion method as shown in the code snippet given below.

[ApiVersion("1.0", Deprecated = true)]

Map to a specific version of an action method

There's another important attribute named MapToApiVersion. You can use it to map to a specific version of an action method. The following code snippet shows how this can be accomplished.

[HttpGet("{id}")]
[MapToApiVersion("2.0")]
public string Get(int id)
{
   return authors[id];
}

Complete API versioning example in ASP.NET Core

Here is the complete source code of the DefaultController for your reference.

[Route("api/[controller]")]
[ApiController]
[ApiVersion("1.0")]
[ApiVersion("1.1")]
[ApiVersion("2.0")]
public class DefaultController : ControllerBase
{
  string[] authors = new string[]
  { "Joydip Kanjilal", "Steve Smith", "Stephen Jones" };
  [HttpGet]
  public IEnumerable<string> Get()
  {
      return authors;
  }
  [HttpGet("{id}")]
  [MapToApiVersion("2.0")]
  public string Get(int id)
  {
     return authors[id];
  }
}

API versioning strategies in ASP.NET Core

There are several ways in which you can version your API in ASP.NET Core. In this section we’ll explore each of them.

Pass version information as QueryString parameters

In this case, you would typically be passing the version information as part of the query string as shown in the URL given below.

http://localhost:25718/api/default?api-version=1.0

Pass version information in the HTTP headers

If you are to pass version information in the HTTP headers, you should set it up in the ConfigureServices method as shown in the code snippet given below.

services.AddApiVersioning(config =>
{
   config.DefaultApiVersion = new ApiVersion(1, 0);
   config.AssumeDefaultVersionWhenUnspecified = true;
   config.ReportApiVersions = true;
   config.ApiVersionReader = new HeaderApiVersionReader("api-version");
});

Once this has been set up, you can invoke an action method pertaining to a specific version of the API as shown in Figure 3.

api versioning 03 IDG

Figure 3

Pass version information in the URL

Yet another method of passing version information is passing version information as part of the route. This is the simplest way of versioning your API but there are certain caveats. First off, if you use this strategy then your clients will need to update the URL whenever a new version of the API is released. Consequently, this approach breaks a fundamental principle of REST that states that the URL of a particular resource should never change.

To implement this versioning strategy, you should specify the route information in your controller as shown below.

[Route("api/v{version:apiVersion}/[controller]")]

The following code listing shows how you can set this up in your controller class.

[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
[ApiVersion("1.0")]
[ApiVersion("1.1")]
public class DefaultController : ControllerBase
    {
        string[] authors = new string[]
        { "Joydip Kanjilal", "Steve Smith", "Stephen Jones" };
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return authors;
        }
        [HttpGet("{id}")]
        [MapToApiVersion("2.0")]
        public string Get(int id)
        {
            return authors[id];
        }
    }

Here is how you can call the default HTTP to get the method of the DefaultController class.

http://localhost:25718/api/v1.0/default

To invoke the other HTTP GET method, i.e., the one that accepts a parameter, specify the following either in the web browser or an HTTP client such as Postman.

http://localhost:25718/api/v2.0/default/1

Deprecate one or more versions of your API

Assume you have multiple versions of your API but you would like to deprecate one or more of them. You can do this easily — you just need to specify the Deprecated property of the ApiVersionAttribute class to true as shown in the code snippet given below.

[ApiController]
[ApiVersion("1.0")]
[ApiVersion("1.1", Deprecated = true)]
[ApiVersion("2.0")]
public class DefaultController : ControllerBase
{
     //Usual code
}

API versioning in ASP.NET Core is now seamless thanks to the introduction of the Microsoft.AspNetCore.Mvc.Versioning package. There are several ways to version your API — you just need to decide the best strategy based on your requirements. You can also use multiple versioning schemes for your API. This adds a lot of flexibility since the clients can choose any of the supported versioning schemes.

How to do more in ASP.NET Core:

Copyright © 2020 IDG Communications, Inc.