Course Content
ASP.NET Core Web API Fundamentials
0/2
Method Safety And Method Idempotency
0/1
Working With OPTIONS and HEAD Requests
0/2
Root Document in ASP.NET Core Web API
0/1
Ultimate ASP.NET Core Web API

Before we continue, let’s create another controller: CompaniesV2Controller (for example’s sake), which will represent a new version of our existing one. It is going to have just one Get action:

using Asp.Versioning;
using CompanyEmployees.Core.Services.Abstractions;
using Microsoft.AspNetCore.Mvc;

namespace CompanyEmployees.Infrastructure.Presentation.Controllers;

[ApiVersion("2.0")]
[Route("api/companies")]
[ApiController]
public class CompaniesV2Controller : ControllerBase
{
    private readonly IServiceManager _service;

    public CompaniesV2Controller(IServiceManager service) => _service = service;

    [HttpGet]
    public async Task<IActionResult> GetCompanies()
    {
        var companies = await _service.CompanyService
            .GetAllCompaniesAsync(trackChanges: false);

        return Ok(companies);
    }
}

By using the [ApiVersion(“2.0”)] attribute, we are stating this controller is version 2.0. After that, let’s version our original controller as well:

[ApiVersion("1.0")]
[Route("api/companies")]
[ApiController]
public class CompaniesController : ControllerBase

If you remember, we configured versioning to use 1.0 as the default API version with this line: opt.AssumeDefaultVersionWhenUnspecified = true;. Therefore, if a client doesn’t state the required version, our API will use this one:

curl --location 'https://localhost:5001/api/companies' 
--header 'Accept: application/json'

Web Api 28.2 - Image 1

If we inspect the Headers tab of the response, we are going to find that controller V1 was assigned for this request:

Web Api 28.2 - Image 2

Of course, you can place a breakpoint in GetCompanies actions in both controllers and confirm which endpoint was hit. Now, let’s see how we can provide a version inside the request.

Using Query String

We can provide a version within the request using a query string in the URI. Let’s test this with an example:

curl --location 'https://localhost:5001/api/companies?api-version=2.0' 
--header 'Accept: application/json'

Web Api 28.2 - Image 3

So, we get the same response body. But, we can inspect the response headers to make sure that version 2.0 is used:

Web Api 28.2 - Image 4

Using URL Versioning

For the URL versioning to work, we have to modify the route in our controller:

[ApiVersion("2.0")]
[Route("api/{v:apiversion}/companies")]
[ApiController]
public class CompaniesV2Controller : ControllerBase

Also, let’s just slightly modify the GetCompanies action in this controller, so we could see the difference in Postman by just inspecting the response body:

[HttpGet]
public async Task<IActionResult> GetCompanies()
{
    var companies = await _service.CompanyService
        .GetAllCompaniesAsync(trackChanges: false);

    var companiesV2 = companies.Select(x => $"{x.Name} V2");

    return Ok(companiesV2);
}

We are creating a projection from our result collection by iterating through each element, modifying the Name property to contain the V2 suffix, and extract it to a new collection companiesV2. Now, we can test it:

curl --location 'https://localhost:5001/api/2.0/companies' 
--header 'Accept: application/json'

Web Api 28.2 - Image 5

One thing to mention, we can’t use the query string pattern to call the CompaniesV2Controller anymore. We can use it for version 1.0, though.

HTTP Header Versioning

If we don’t want to change the URI of the API, we can send the version in the HTTP Header. To enable this, we have to modify our configuration:

public static void ConfigureVersioning(this IServiceCollection services)
{
    services.AddApiVersioning(opt =>
    {
        opt.ReportApiVersions = true;
        opt.AssumeDefaultVersionWhenUnspecified = true;
        opt.DefaultApiVersion = new ApiVersion(1, 0);
        opt.ApiVersionReader = new HeaderApiVersionReader("api-version");
    }).AddMvc();
}

And to revert the Route change in our controller:

[ApiVersion("2.0")]
[Route("api/companies")]
[ApiController]
public class CompaniesV2Controller : ControllerBase

Let’s test these changes:

curl --location 'https://localhost:5001/api/companies' 
--header 'Accept: application/json' 
--header 'api-version: 2.0'

Web Api 28.2 - Image 6

If we want to support query string versioning, we should use a new QueryStringApiVersionReader class instead:

opt.ApiVersionReader = new QueryStringApiVersionReader("api-version");

0% Complete