Asp-Net-Core Development Notes: API Version Management
For Web API applications, as time passes and requirements increase or change, the API will inevitably encounter the need for upgrades. In fact, Web API applications should consider API versioning from the moment they are created. Changes in business logic, addition of features, removal or renaming of endpoints, modifications to endpoint parameters, and additions, deletions, or changes to entity properties will all alter the API's functionality, thereby leading to version changes.
目录9 个章节
Preface
For Web API applications, as time progresses and requirements increase or change, APIs will inevitably encounter the need for upgrades. In fact, Web API applications should consider API versioning from the very beginning of their creation. Business adjustments, feature additions, endpoint removals and renaming, changes in endpoint parameters, as well as adding, removing, or modifying entity properties can all alter API functionality, thus resulting in version changes.
Most existing resources use the Microsoft.AspNetCore.Mvc.Versioning package, but upon actual use, I found that this package has long been discontinued. Microsoft's official documentation also seems to lack information on this. However, the package's NuGet page indicates it has been replaced by the new Asp.Versioning.Mvc package. It turns out Microsoft's renaming department has been at it again—my apologies for the oversight! 😂
Fortunately, this new package has detailed documentation on GitHub, but the speed of renaming is quite astonishing. In order to implement this functionality, I took quite a few detours. 😂
OK, this article is based on .Net6.0 and uses AspNetCore WebApi as an example to introduce the process of incorporating API version management.
Basics
There are two ways to specify a version: you can either use the [ApiVersion] attribute or the version convention approach. Once different versions of an API interface are defined, clients can access a specific version of the API through several methods as follows:
- Using the URL path, e.g.,
api/v1.0/values - Using a query string, e.g.,
api/values?api-version=1.0 - Using a custom HTTP header
- Using a Media Type parameter, e.g.,
Accept: application/json;v=2.0
The default method in ASP.NET Core MVC is using a query string, with the parameter name api-version. The specific method to use is determined by the server (configured using the ApiVersionReader property introduced below), and it can be one of the methods or multiple methods used simultaneously.
The API version format consists of a major version number and a minor version number, and it can also include two optional parts: a version group and a status.
[Version Group.]<Major>.<Minor>[-Status]<Version Group>[<Major>[.Minor]][-Status]
The version group format is YYYY-MM-DD and serves to logically group API interfaces, while the status indicates the current state of the version, such as Alpha, Beta, and RC. Here are some common version formats:
/api/foo?api-version=1.0/api/foo?api-version=2.0-Alpha/api/foo?api-version=2015-05-01.3.0/api/v1/foo/api/v2.0-Alpha/foo/api/v2015-05-01.3.0/foo
This article uses the format /api/v1/foo.
Installing Dependencies
You need to install these two NuGet packages:
- Asp.Versioning.Mvc
- Asp.Versioning.Mvc.ApiExplorer
Register Services
Edit the Program.cs file
builder.Services.AddApiVersioning(options => {
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
options.ApiVersionReader = ApiVersionReader.Combine(
new UrlSegmentApiVersionReader(),
new HeaderApiVersionReader("x-api-version"),
new MediaTypeApiVersionReader("ver")
);
})
.AddMvc()
.AddApiExplorer(options => {
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
The code above does the following:
DefaultApiVersionsets the default version to 1.0.AssumeDefaultVersionWhenUnspecifieduses the default version when no version is specified.ReportApiVersionsadds available API versions to the response headers.ApiVersionReaderdefines that API version information can be retrieved from three places: the URL and two request headers.GroupNameFormatspecifies the format for version names, see the table below for details.SubstituteApiVersionInUrlis set to true because URL-based versioning is being used.
API Version Format Strings
In this article, I use the 'v'VVV format
| Format Specifier | Description | Examples |
|---|---|---|
| F | Full API version as [group version][.major[.minor]][-status] | 2017-05-01.1-RC -> 2017-05-01.1-RC |
| FF | Full API version with optional minor version as [group version][.major[.minor,0]][-status] | 2017-05-01.1-RC -> 2017-05-01.1.0-RC |
| G | Group version as yyyy-MM-dd | 2017-05-01.1-RC -> 2017-05-01 |
| GG | Group version as yyyy-MM-dd with status | 2017-05-01.1-RC -> 2017-05-01-RC |
| y | Group version year from 0 to 99 | 2001-05-01.1-RC -> 1 |
| yy | Group version year from 00 to 99 | 2001-05-01.1-RC -> 01 |
| yyy | Group version year with a minimum of three digits | 2017-05-01.1-RC -> 017 |
| yyyy | Group version year as a four-digit number | 2017-05-01.1-RC -> 2017 |
| M | Group version month from 1 through 12 | 2001-05-01.1-RC -> 5 |
| MM | Group version month from 01 through 12 | 2001-05-01.1-RC -> 05 |
| MMM | Group version abbreviated name of the month | 2001-06-01.1-RC -> Jun |
| MMMM | Group version full name of the month | 2001-06-01.1-RC -> June |
| d | Group version day of the month, from 1 through 31 | 2001-05-01.1-RC -> 1 |
| dd | Group version day of the month, from 01 through 31 | 2001-05-01.1-RC -> 01 |
| ddd | Group version abbreviated name of the day of the week | 2001-05-01.1-RC -> Mon |
| dddd | Group version full name of the day of the week | 2001-05-01.1-RC -> Monday |
| v | Minor version | 2001-05-01.1-RC -> 1 1.1 -> 1 |
| V | Major version | 1.0-RC -> 1 2.0 -> 2 |
| VV | Major and minor version | 1-RC -> 1 1.1-RC -> 1.1 1.1 -> 1.1 |
| VVV | Major, optional minor version, and status | 1-RC -> 1-RC 1.1 -> 1.1 |
| VVVV | Major, minor version, and status | 1-RC -> 1.0-RC 1.1 -> 1.1 1 -> 1.0 |
| S | Status | 1.0-Beta -> Beta |
| p | Padded minor version with default of two digits | 1.1 -> 01 1 -> 00 |
| p[n] | Padded minor version with N digits | p2: 1.1 -> 01 p3: 1.1 -> 001 |
| P | Padded major version with default of two digits | 2.1 -> 02 2 -> 02 |
| P[n] | Padded major version with N digits | P2: 2.1 -> 02 P3: 2.1 -> 002 |
| PP | Padded major and minor version with a default of two digits | 2.1 -> 02.01 2 -> 02.00 |
| PPP | Padded major, optional minor version, and status with a default of two digits | 1-RC -> 01-RC 1.1-RC -> 01.01-RC |
| PPPP | Padded major, minor version, and status with a default of two digits | 1-RC -> 01.00-RC 1.1-RC -> 01.01-RC |
Setting Up API Versions
The example interface has two versions:
- /api/v1/demo/test
- /api/v2/demo/test
Create two directories under the Controller, v1 and v2, then create a Controller in each respectively.
Here's the code for Controllers/v1/DemoController.cs:
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion(1.0)]
[ApiController]
public class DemoController : ControllerBase {
[HttpGet("[action]")]
public ApiResponse Test() {
return ApiResponse.Ok("version=1.0");
}
}
The other version of the interface Controllers/v2/DemoController.cs:
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion(2.0)]
[ApiController]
public class DemoController : ControllerBase {
[HttpGet("[action]")]
public ApiResponse Test() {
return ApiResponse.Ok("version=2.0");
}
}
As you can see, to distinguish between different versions of the interface, you only need to add the [ApiVersion(2.0)] attribute.
Since I want to use the URL to select different versions of the interface, the route needs to be configured as "api/v{version:apiVersion}/[controller]".
If you don't include the version number in the URL, you can also pass it using a request parameter, for example, /api/demo/test?api-version=1.0.
This can be configured in the ApiVersionReader attribute.
Configuring Swagger
Swagger has essentially become the standard for API documentation, but I've noticed many articles overlook this part. (Fortunately, the official documentation didn't forget.)
First, create a configuration class.
public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions> {
readonly IApiVersionDescriptionProvider provider;
public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) =>
this.provider = provider;
public void Configure(SwaggerGenOptions options) {
foreach (var description in provider.ApiVersionDescriptions) {
options.SwaggerDoc(
description.GroupName,
new OpenApiInfo() {
Title = $"Example API {description.ApiVersion}",
Version = description.ApiVersion.ToString(),
});
}
}
}
Registering Services
builder.Services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
Configuring Middleware
app.UseSwagger();
app.UseSwaggerUI(options => {
foreach (var description in app.DescribeApiVersions()) {
var url = $"/swagger/{description.GroupName}/swagger.json";
var name = description.GroupName.ToUpperInvariant();
options.SwaggerEndpoint(url, name);
}
});
Effects & Testing
Done. Access the swagger documentation, and in the upper right corner, the API grouping (接口分组) shows different versions.

Request https://localhost:7053/api/v1/Demo/Test
The API returns:
{
"statusCode": 200,
"successful": true,
"message": "version=1.0",
"data": null,
"errorData": null
}
Request https://localhost:7053/api/v2/Demo/Test
The API returns:
{
"statusCode": 200,
"successful": true,
"message": "version=2.0",
"data": null,
"errorData": null
}
Not bad~ 😃
References
_EOF_
Asp-Net-Core Development Notes: API Version Management
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
Asp-Net-Core开发笔记:使用NPM和gulp管理前端静态文件
前言 本文介绍的是AspNetCore的MVC项目,WebApi+独立前端这种前后端分离的项目就不需要多此一举了~默认前端小伙伴是懂得使用前端工具链的。 为啥要用MVC这种服务端渲染技术呢? 简单项目不需要强行分离增加复杂度(如:我正在开发的博客项目) 后端渲染利于SEO,对博客网站友好 OK,虽然MVC的技术老了点,但依然可以结合现代前端工具链来提高效率 本文的食用需要先安装好Node.js环境
2022-02-17 · Asp-Net-Core开发笔记 · 约 1 分钟
Asp-Net-Core开发笔记:使用原生的接口限流功能
试用了一下,感觉还是太折腾,用回原来的 AspNetCoreRateLimit 组件得了
2024-05-22 · Asp-Net-Core开发笔记 · 约 1 分钟
AspNetCore开发笔记:WebApi项目集成企业微信和公众号
微信开发文档烂得离谱,直接用SKIT库搞定。异步处理消息,图片下载内存处理,公众号被动回复5秒内搞定。啧啧。
2025-12-22 · Asp-Net-Core开发笔记 · 约 1 分钟
Asp-Net-Core开发笔记:Oracle调优
Supported Connection String Attributes To obtain an OracleConnection object in a .NET stored procedure that represents the implicit database connection, set the ConnectionString property of the Oracle
2023-03-05 · Asp-Net-Core开发笔记 · 约 1 分钟
讨论
共 0 条加载评论中…