In this post, we will see how to manage the versioning in a .net core Web API service, using three different approaches:
1) Query String-Based Versioning
2) URL-Based Versioning
3) HTTP Header-Based Versioning
First of all, we open Visual Studio 2019 and we create a Web API project:




If we run the application, this will be the output:

Now, in order to manage the versioning, we have to install the library
Microsoft.AspNetCore.Mvc.Versioning
and then, we have to modify the method ConfigureServices in the startup file:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddApiVersioning(o =>
{
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1, 0);
});
}
QUERY STRING-BASED VERSIONING:
We open the file WeatherForecastController and we create two versions of the controller:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
namespace WebAPIVersioning.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/Forecast")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
[ApiController]
[ApiVersion("2.0")]
[Route("api/Forecast")]
public class WeatherForecastControllerVersion2 : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastControllerVersion2(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}
In order to call the different versions of the controller, we have to pass the version of controller in the query string:


URL-BASED VERSIONING:
We open the file WeatherForecastController and we create two versions of the controller:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
namespace WebAPIVersioning.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{v:apiVersion}/Forecast")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
[ApiController]
[ApiVersion("2.0")]
[Route("api/v{v:apiVersion}/Forecast")]
public class WeatherForecastControllerVersion2 : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastControllerVersion2(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}
In order to call the different versions of the controller, we have to put the version of controller in an URL path segment:


HTTP HEADER-BASED VERSIONING:
We open the file WeatherForecastController and we create two versions of the controller:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
namespace WebAPIVersioning.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/Forecast")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
[ApiController]
[ApiVersion("2.0")]
[Route("api/Forecast")]
public class WeatherForecastControllerVersion2 : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastControllerVersion2(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}
Finally, we have to modify the method ConfigureServices, in the the startup file:
[STARTUP.CS]
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddApiVersioning(o =>
{
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1, 0);
o.ApiVersionReader = new HeaderApiVersionReader("x-api-version");
});
}
Now, we run the application using Postman and we put in the header the controller’s version:

