ASP.Net Core Web API Versioning

In this tutorial, we are going to see how to support versioning for ASP.Net Core Web API endpoints. Versioning helps API owners to roll out enhanced functionalities to different customers on a time to time basis without breaking the old versions of endpoints. In previous versions of ASP.Net, we used to create a custom IHttpControllerSelector through which we will route the request to appropriate controller version based on custom header or URL pattern. In ASP.Net Core, we will use aspnet-api-versioning middleware (created by Chris Martinez).

Primarily API versioning can be done either through URL or with custom header. I personally prefer custom header approach, because in this case URL’s will be much cleaner and more inclined towards Restful nature.

NOTE: Updated this tutorial on 2/27/2017 with MSBuild based Dotnet SDK.

Create an ASP.Net Core Application using VS 2017. I am using following version of Dotnet SDK which is based on MSBuild/CSProj (remember that previous versions of ASP.Net Core are based on Project.json/XProj.).

 image

Add the following package dependency to the project file.

<ItemGroup>
  <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
  <PackageReference Include="Microsoft.AspNetCore" Version="1.0.3" />
  <PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="1.1.0" />
  <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.0.2" />
  <PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="1.0.3" />
  <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.0.1" />
  <PackageReference Include="Newtonsoft.Json" Version="10.0.1-beta1" />
</ItemGroup>

Now lets configure the versioning middleware in ConfigureServices method of Startup class.

public void ConfigureServices(IServiceCollection services)
{
    services.AddApiVersioning(options =>
    {
        options.ReportApiVersions = true;
        options.AssumeDefaultVersionWhenUnspecified = true;
        options.ApiVersionReader = new HeaderApiVersionReader("api-version");
        options.DefaultApiVersion = new Microsoft.AspNetCore.Mvc.ApiVersion(2, 0);
        options.ApiVersionSelector = new CurrentImplementationApiVersionSelector(options);
    });
    services.AddMvc();
}

As shown above, we have different configuration options available for API versioning middleware.

ReportApiVersions: Will be used to send the supported API version in response to the client.

AssumeDefaultVersionWhenUnspecified: Will be used to serve the request without a version. The assumed API version by default would be 1.0.

ApiVersionReader: This is used to configure the way API version is passed to server from client – Query string or Request Header. In above sample, I have used custom Request header called api-version. We can create our own implementations of IApiVersionReader to support other formats like Accept header.

DefaultApiVersion: This property is used to specify default API version to be used when no version is specified in the request. This will default the version to 1.0.

ApiVersionSelector: This property is used to get more control on version selection process. If no API version is specified in the request and we want to have a default API version selection based on custom logic, then this property can be used. For example, lets say we have four versions – 1.0, 2.0, 3.0, 3.1-alpha. In above sample we have used Current Implementation Selector, now when a request comes without a version, then the latest stable version will be used i.e., 3.0. Similarly we can create our own implementation of IApiVersionSelector and have our own custom logic. If the outcome of this property got no match, then the logic will be fall backed to DefaultApiVersion.

There are other properties like CreateBadRequest (which can be used to send version related bad responses to client for example version not found) and Conventions (used to configure the versions for controllers and actions without using attributes through HasApiVersion and MapToApiVersion extension methods).

Lets create different API versions of same controller under different namespaces as shown below.

using Microsoft.AspNetCore.Mvc;

namespace AspNetCoreWebApi.Controllers1
{
    [ApiVersion("1.0")]
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        [HttpGet]
        public IActionResult Get() => Ok(new string[] { "value1" });
    }
}
namespace AspNetCoreWebApi.Controllers2
{
    [ApiVersion("2.0")]
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        [HttpGet]
        public IActionResult Get() => Ok(new string[] { "value2"});
    }
}

namespace AspNetCoreWebApi.Controllers3
{
    [ApiVersion("3.0")]
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        [HttpGet]
        public IActionResult Get() => Ok(new string[] { "value3" });
    }
}

namespace AspNetCoreWebApi.Controllers4
{
    [ApiVersion("3.1-alpha")]
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        [HttpGet]
        public IActionResult Get() => Ok(new string[] { "value3.1" });
    }
}

Now lets use Postman tool to evaluate the results.

When we make a request without an API version, we will get 3.0 results. This is because we have selected ApiVersionSelector to CurrentImplementationApiVersionSelector. If we remove CurrentImplementationApiVersionSelector, we will get 2.0 results because DefaultApiVersion is configured to 2.0.

image

Lets make a request with api-version header pointed to 3.1-alpha. We will 3.1-alpha version results.

image

If we look at the response headers, we will get the allowed versions.

image

That’s it for now, Happy Coding and Stay Tuned!!!

You may also like...