前言
项目持续维护, API 就需要版本控制. ASP.NET Core 有官方的插件专门处理 API 版本控制哦.
主要参考
Your Guide to REST API Versioning in ASP.NET Core
How to use API versioning in ASP.NET Core
ASP.NET Core WebApi版本控制的实现 (有讲到 swagger 哦)
Asp.Net Core 5 - API Versioning
安装 nuget
dotnet add package Microsoft.AspNetCore.Mvc.Versioning
Program.cs
using Microsoft.AspNetCore.Mvc; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddApiVersioning(options => { options.AssumeDefaultVersionWhenUnspecified = true; // 如果请求没有声明就使用默认版本 options.DefaultApiVersion = new ApiVersion(1, 0); // 默认版本 options.ReportApiVersions = true; // 在 header 返回支持的版本 (尤其用于 deprecated 弃用的 API) }); //builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { //app.UseSwagger(); //app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
这个是 ASP.NET Core 6.0 的版本哦, 主要看 .AddApiVersioning, Swagger 我注释掉是因为 versioning 和 swagger 有时候会打架.
By default, 它是用 request query string 声明 version 的, 这个通常我们不喜欢,我们喜欢在 url path 里面声明. 最好也不要有 default version 的概念. 因为竟然都分 version 了咯, 就分清清楚楚丫.
两种管理方式
1. 一个 controller 多个 version
namespace WebApiVersioning.Controllers { [ApiController] // 表示这个 Controller 支持 1.0 和 2.0 [ApiVersion("1.0", Deprecated = true)] // Deprecated 表示废弃了, 会在返回的 header 表示, 虽然是废弃了, 但是依然会跑和 response 的哦 (自行处理) [ApiVersion("2.0")] [Route("api/v{version:apiVersion}/[controller]")] // 声明 version in path public class WeatherForecastController : ControllerBase { [HttpGet(Name = "GetWeatherForecast"), MapToApiVersion("1.0")] // 通过 MapToApiVersion 声明这个 action 是 for 哪个 version public IEnumerable<WeatherForecast> Get_v1() // 名字是 v1 { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); } [HttpGet(Name = "GetWeatherForecast"), MapToApiVersion("2.0")] public IEnumerable<WeatherForecast> Get_v2() // 名字是 v2 { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); } private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; } }
把多个 version 放 1 个 controller 会和 swagger 打架哦 (因为 swagger 不允许 action same path), 虽然很方便但是我觉得可能不顺风水哦.
请求 v1.0 就会执行 Get_v1, v2.0 就是 Get_v2
header response 都会表示 api-supported-versions 和 api-deprecated-versions (如果有).
如果都没有 deprecated, 会这样
2. 1 个 controller 一个 version
通过 namespace 来区分 version, 或者通过 controller 不同名字来做 version 也是可以的.
namespace WebApiVersioning.Controllers.v1 { [ApiController] [ApiVersion("1.0")] [Route("api/v{version:apiVersion}/[controller]")] public class WeatherForecastController : ControllerBase { [HttpGet(Name = "GetWeatherForecast")] public IEnumerable<WeatherForecast> Get() { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); } private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; } } namespace WebApiVersioning.Controllers.v2 { [ApiController] [ApiVersion("2.0")] [Route("api/v{version:apiVersion}/[controller]")] public class WeatherForecastController : ControllerBase { [HttpGet(Name = "GetWeatherForecast")] public IEnumerable<WeatherForecast> Get() { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); } private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; } }
Non-version
有些 API 不需要 version control 的话, 用这个 attribute 就可以了
[ApiVersionNeutral]