Click here to Skip to main content
13,139,496 members (57,245 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

2K views
2 bookmarked
Posted 1 Sep 2017

Versioning ASP.NET Core 2.0 Web API

, 1 Sep 2017
Rate this:
Please Sign up or sign in to vote.
How to implement versioning in ASP.NET Core Web API. Continue reading

Problem

How to implement versioning in ASP.NET Core Web API.

Solution

Create an empty project, add NuGet packages:

  • Microsoft.AspNetCore.Mvc.Versioning

Update Startup class to add services and middleware for MVC:

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

            services.AddMvc();
        }

        public void Configure(
            IApplicationBuilder app, 
            IHostingEnvironment env)
        {
            app.UseDeveloperExceptionPage();
            app.UseMvcWithDefaultRoute();
        }

Add controllers for different versions that can be accessed via query string:

/movies?api-version=2.0

    [ApiVersion("1.0")]
    [Route("movies")]
    public class MoviesControllerV1 : Controller
    {
        [HttpGet]
        public IActionResult Get() => Content("Version 1");
    }

    [ApiVersion("2.0")]
    [Route("movies")]
    public class MoviesControllerV2 : Controller
    {
        [HttpGet]
        public IActionResult Get() => Content("Version 2");
    }

Add controllers for different versions that can be accessed via URL:

/actors/v2.0

    [ApiVersion("1.0")]
    [Route("actors/v{ver:apiVersion}")]
    public class ActorsControllerV1 : Controller
    {
        [HttpGet]
        public IActionResult Get() => Content("Version 1");
    }

    [ApiVersion("2.0")]
    [Route("actors/v{ver:apiVersion}")]
    public class ActorsControllerV2 : Controller
    {
        [HttpGet]
        public IActionResult Get() => Content("Version 2");
    }

Add controllers for different versions that can be accessed via HTTP Header:

/reviews

    [ApiVersion("1.0")]
    [Route("reviews")]
    public class ReviewsControllerV1 : Controller
    {
        [HttpGet]
        public IActionResult Get() => Content("Version 1");
    }

    [ApiVersion("2.0")]
    [Route("reviews")]
    public class ReviewsControllerV2 : Controller
    {
        [HttpGet]
        public IActionResult Get() => Content("Version 2");
    }

You can pass header using Postman:

Discussion

As your Web API changes you would need to add versioning support in order for clients to continue working correctly. Adding versioning support in ASP.NET Core involves first configuring services in Startup and then choosing a versioning strategy i.e. via query string, URL or HTTP header.

Note: I prefer using HTTP headers to supply version number as it keeps the URL free of clutter, however, you could choose option better suited for your needs.

Configuring Services

During configuration you could set following properties:

  • ReportApiVersions: adds a response header api-supported-versions.
  • AssumeDefaultVersionWhenUnspecified: clients that don’t specify version, default will be used, otherwise they will get an error (UnsupportedApiVersion).
  • DefaultApiVersion: specify default version number using ApiVersion
  • ApiVersionReader: specify the location from where version v is read. The default is query string however, to use HTTP header, you need to specify this (see section below).
  • Conventions: instead of using [ApiVersion] attribute, you could specify versions of various controllers here (see section below).

Note: you could read the current version of request by using GetRequestedApiVersion method on HttpContext, which returns ApiVersion type.

Query String

The default method of specifying version number is via query string api-version parameter.

URL

You could use a route and apiVersion constraint to specify version number in the URL. Note that specifying version in query string will no longer work (it will be ignored since the route will hit a specific controller):

[ApiVersion("2.0")]
    [Route("actors/v{ver:apiVersion}")]
    public class ActorsControllerV2 : Controller

HTTP Header

To use HTTP headers to pass in version number, you need to first configure the version reader, which tells the middleware how to read version. Once this option is configured, specifying version in query string won’t work:

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

Note that you can choose the header key however, I’ve used “api-version” just to keep it consistent with query string and URL based methods.

Conventions

Instead of using [ApiVersion] attribute, you could configure version numbers on controllers by using Conventions property:

options.Conventions.Controller<WritersControllerV1>()
                    .HasApiVersion(new ApiVersion(1, 0));

                options.Conventions.Controller<WritersControllerV2>()
                    .HasApiVersion(new ApiVersion(2, 0));

Now the controllers don’t need any extra attributes:

[Route("writers")]
    public class WritersControllerV1 : Controller
    {
        [HttpGet]
        public IActionResult Get() => Content("Version 1");
    }
    
    [Route("writers")]
    public class WritersControllerV2 : Controller
    {
        [HttpGet]
        public IActionResult Get() => Content("Version 2");
    }

Versioning Action Methods

You could also version action methods within a controller using [MapToApiVersion] attribute:

[ApiVersion("1.0")]
    [ApiVersion("2.0")]
    [Route("directors")]
    public class DirectorsController : Controller
    {
        [HttpGet]
        public IActionResult Get() => Content("Version 1");

        [HttpGet, MapToApiVersion("2.0")]
        public IActionResult GetV2() => Content("Version 2");
    }

Deprecating Versions

You could specify whether a version of API is deprecated by setting Deprecated property on the [ApiVersion] attribute:

[ApiVersion("1.0", Deprecated = true)]
    [Route("genres")]
    public class GenresControllerV1 : Controller
    {
        [HttpGet]
        public IActionResult Get() => Content("Version 1");
    }

    [ApiVersion("2.0")]
    [Route("genres")]
    public class GenresControllerV2 : Controller
    {
        [HttpGet]
        public IActionResult Get() => Content("Version 2");
    }

Note that this doesn’t stop clients from using the version and will only output response headers:

Source Code

GitHub: https://github.com/TahirNaushad/Fiver.Api.Versioning

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Tahir Naushad
Software Developer (Senior)
United Kingdom United Kingdom
Qualified and skilled professional with experience working as a Software Developer, Technical Lead and Architect. I have worked on windows, web and distributed applications using the latest set of technologies within the Microsoft .NET ecosystem. I have lead teams using agile methodologies and trained developers in writing well-designed and maintainable software applications.

Currently focusing on ASP.NET Core, C#, Azure, Angular and Domain Driven Design.

You may also be interested in...

Comments and Discussions

 
-- There are no messages in this forum --
Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.170915.1 | Last Updated 1 Sep 2017
Article Copyright 2017 by Tahir Naushad
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid