ASP.NET Core – Web API Versioning
前言
项目持续维护, 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
Docs – aspnet-api-versioning(最新版本,上面的是旧版本的参考)
安装 nuget
dotnet add package Asp.Versioning.Mvc
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) }).AddMvc(); //builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { //app.UseSwagger(); //app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
主要是 .AddApiVersioning 的配置.
注释掉 Swagger 是因为 versioning 会导致 Swagger 需要额外配置. 看这篇: Swagger API Versioning.
两种管理方式
第一种方式: 一个 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)] + " v1" }) .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)] + " v2" }) .ToArray(); } private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; } }
请求 v1.0 就会执行 Get_v1, v2.0 就是 Get_v2
header response 会表示 api-supported-versions 和 api-deprecated-versions (如果有).
如果都没有 deprecated, 会是这样
第二种方式: 1 个 controller 一个 version
可以通过 namespace 或者 controller name 来设定版本号, 关键就是不要把 Action 放一起.
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)] + " v1" }) .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)] + " v2" }) .ToArray(); } private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; } }
两种方法各有所长. 并用是可以的.
Non-version
不需要 API versioning 的就加上 attribute
[ApiVersionNeutral]
Range Version
当我们发布新的 version 时,绝大部分的 API 是向后兼容的,所以在 define API version 时,我们会希望这样写 "^1.0" 表示 1.0 - 1.9 都可以用。
[HttpGet, MapToApiVersion("^1.0")] public IEnumerable<Product> Get_v1() { return [ new () { Id = 1, Name = "p1" }, new () { Id = 2, Name = "p1" } ]; }
但它不支持,你唯一能做的是写多几个 MapToApiVersion("1.1"), MapToApiVersion("1.2")
相关 feature request 很少就有提了 Github – API range attribute,并且他们也做了一个扩展来支持 PB.ITOps.AspNetCore.Versioning。
不清楚还有没有人在维护。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 百万级群聊的设计实践
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
2018-10-25 Angular 学习笔记 (Material Datepicker)