API Versioning in .Net Core

api10

You can find my all .Net core posts here.

In this post, we will see how to use different options for versioning in .Net Core API projects.

Versioning API is very important and it should be implemented in the API project.

Let us see how to achieve this in .Net Core.

prerequisite:

  • Visual studio 2017 community edition, download here
  • .Net Core 2.0 SDK from here (I have written a post to install SDK here)

Create the API application using .Net Core 2.0 template in VS 2017

Once you have all these installed, open your Visual Studio 2017 -> Create New Project -> Select Core Web application:

api1

Click on Ok and in next window, select API as shown below:

api2

Visual Studio will create a well-structured application for you.

Install Nuget package for API Versioning

The first step is to install the Nuget package for API Versioning.

Search with “Microsoft.AspNetCore.Mvc.Versioning” in Nuget Package Manager and click on Install:

api3

This Nuget package is a service API versioning library for Microsoft ASP.NET Core.

Changes in Startup Class

Once the Nuget package is installed, next step is to add API Versioning service in the ConfigureService method as shown below:


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

Some points here:

  • ReportApiVersions flag is used to add the API versions in the response header as shown below:

api4

  • AssumeDefaultVersionWhenUnspecified flag is used to set the default version when the client has not specified any versions. Without this flag, UnsupportedApiVersion exception would occur in the case when the version is not specified by the client
  • DefaultApiVersion flag is used to set the default version count

Create Multiple versions of the sample API

Once the API versioning service is added, next step is to create multiple versions of our Values API.

For now just keep the Get method and remove rest of the method and create version 2 of the same API as shown below:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace ApiVersioningSampleApp.Controllers
{
[ApiVersion("1.0")]
[Route("api/Values")]
public class ValuesV1Controller : Controller
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "Value1 from Version 1", "value2 from Version 1" };
}
}

[ApiVersion("2.0")]
[Route("api/Values")]
public class ValuesV2Controller : Controller
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1 from Version 2", "value2 from Version 2" };
}
}
}

In above code:

  • We have applied the attribute [ApiVersion(“1.0”)] for Version 1
  • We have applied the attribute [ApiVersion(“2.0”)] for Version 2
  • Also changed the Get value to understand which version is getting called

Just run your application and you will see the Version 1 API is getting because when we do not specify any specific version, default version (1.0 in our case) would be called:

api5

 

There are some ways by which you can specify the version of the API which is as below.

Query String based versioning

In this, you can specify the version of the API in the query string, for example, to call the version 2 of Values API, below would work:

/api/values?api-version=2.0

api6

URL based versioning

There are many people who do not like query based pattern, in such case we can implement URL based versioning by changing the route as shown below:

[Route(“api/{v:apiVersion}/Values”)]

In such case, below call will return the version 2 of the API:

/api/2.0/values

api7

This approach is more readable.

HTTP Header based Versioning

If you do not wish to change the URL of the API then you can send the version of API in the HTTP header.

To enable this, Version reader needs to be added to the ConfigureService method as below:


o.ApiVersionReader = new HeaderApiVersionReader("x-api-version");

Once you enable this, Query string approach would not work. If you wish you enable both of them then just use below code:


o.ApiVersionReader = new QueryStringOrHeaderApiVersionReader("x-api-version");

Once API Version reader is enabled, you can specify the API version while calling this particular API. For example, I have given Version 1 while calling the API from Postman:

api8

Some useful features

Deprecating the versions

Sometimes we need to deprecate some of the versions of the API, but we do not wish to completely remove that particular version of the API.

In such case, we can set the Deprecated flag to True for that API as shown below:


[ApiVersion("1.0", Deprecated = true)]
[Route("api/Values")]
public class ValuesV1Controller : Controller
{

//// Code

}

It will not remove this version of API but it will return the list of deprecated versions in the header api-deprecated-versions as shown below:

api9

Assign the versions using conventions

If you have lots of versions of the API, instead of putting the ApiVersion attribute on all the controller, we can assign the versions using conventions property.

In our case, we can add the convention for both the versions as below:


o.Conventions.Controller<ValuesV1Controller>().HasApiVersion(new ApiVersion(1, 0)); 
o.Conventions.Controller<ValuesV2Controller>().HasApiVersion(new ApiVersion(2, 0));

Which means, we are not required to put [ApiVersion] attributes above the controller

API Version Neutral

There might be a case when we need to opt out the version for some specific APIs.
For example, Health checking APIs which are used to ping. In such case, we can opt this API out by adding attribute [ApiVersionNeutral] as shown below:
[ApiVersionNeutral] 
[RoutePrefix( "api/[controller]" )] 
public class HealthCheckController : Controller {
////Code
}

Apart from this, we can use other features as below:

  • Add  MapToApiVersion in the attribute if you wish to apply versioning only for specific action method instead of the whole controller. For example:

[HttpGet, MapToApiVersion("2.0")]
public IEnumerable<string> Get()
{
return new string[] { "value1 from Version 2", "value2 from Version 2" };
}

  • We can get the version information from the method HttpContext.GetRequestedApiVersion();, this is useful to check which version has been requested by the client
  • Version Advertisement can be used by which each service will advertise the supported and deprecated API versions it knows about. This is generally used when the service API versions are split across hosted applications
  • We can allow clients to request a specific API version by media type. This option can be enabled by adding below line in the API versioning options in the ConfigureService method:

options => options.ApiVersionReader = new MediaTypeApiVersionReader();

Hope it helps.

 

 

 

 

Advertisements

7 thoughts on “API Versioning in .Net Core

  1. You have great acumen writing on subject matter. This is an excellent article, as are the other articles you post. You have any skill level covered by walking through even the those elementary steps in each article! So many authors get ‘lazy’ on this point and would say something to the effect “If you need a refresher on how to install Visual Studio, see my other article here….”.

    I hope you write a book on ASP.NET Core someday. Your procedural discipline explaining the subject matter and your ability to communicate clearly demonstrates a standard I believe all should follow. Cheers.

    Like

    1. Thanks a lot for your kind words John. I am glad that you noticed the mandatory steps I add to all posts so that it becomes a complete post. I will surely plan to write a book but currently, time is a constraint.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s