ASP.NET Core 6+需用Microsoft.AspNetCore.Mvc.Versioning实现API版本控制,仅加[ApiVersion]无效,必须配合[Route("api/v{version:apiVersion}/[controller]")]绑定URL段,且AddApiVersioning()须配置AssumeDefaultVersionWhenUnspecified、ReportApiVersions和ApiVersionReader三项关键选项。

ASP.NET Core 6+ 原生支持 API 版本控制,不用自己解析 URL 段或手动读取 api-version 查询参数——直接用 Microsoft.AspNetCore.Mvc.Versioning,否则你写的路由逻辑、Swagger 文档、过滤器都会和版本脱节。
为什么只加 [ApiVersion("1.0")] 不生效
框架不会自动把 /api/v1/users 映射到标了 [ApiVersion("1.0")] 的控制器。它只声明“这个 Controller 支持 v1”,但没告诉路由系统“v1 对应哪段 URL”。必须配合路由模板显式绑定。
-
[Route("api/v{version:apiVersion}/[controller]")]是最常用写法,apiVersion是内置路由约束,能识别v1、v2.5等格式 - 控制器上必须同时有
[ApiVersion("1.0")]和匹配的[Route],缺一不可 - 如果想让一个 Action 只响应特定子版本(比如仅 v1.1),要用
[MapToApiVersion("1.1")],不能只靠[ApiVersion] - 不加
[Route]或路由模板里没含{version},请求会 404,而不是 400 —— 因为根本没进版本协商流程
AddApiVersioning() 必须配置的三项关键选项
在 Program.cs 中调用 AddApiVersioning() 时,以下三个配置项直接影响行为,漏掉任一个都可能让版本控制“看起来没起作用”:
-
AssumeDefaultVersionWhenUnspecified = true:客户端不传任何版本时,默认走DefaultApiVersion(如new ApiVersion(1, 0)),否则直接返回 400 Bad Request -
ReportApiVersions = true:响应头里自动加api-supported-versions和api-deprecated-versions,前端可据此判断兼容性 -
ApiVersionReader要明确指定,例如new UrlSegmentApiVersionReader()(对应/v1/)或new QueryStringApiVersionReader("api-version")(对应?api-version=1.0),多个可共存
Swagger 多版本文档生成总为空或混在一起
默认 AddSwaggerGen() 不知道哪个接口属于哪个版本,必须手动按 [ApiVersion] 属性筛选文档。否则所有接口都塞进同一个 v1 文档里,或者干脆漏掉高版本。
- 注册多个
SwaggerDoc()时,docName(如"v1")必须和[ApiVersion("1.0")]中的版本字符串能对上(建议统一用"v1"、"v2"这种字符串) -
DocInclusionPredicate必须检查控制器类型上的ApiVersionAttribute,不能只看 Action 方法——因为版本是按 Controller 维度声明的 -
ResolveConflictingActions必须设为apiDescriptions => apiDescriptions.First(),否则同一路径多版本会报“冲突”错误
同一 Controller 支持多个版本时的常见陷阱
想让 UsersController 同时处理 v1 和 v2,不是简单叠加 [ApiVersion("1.0"), ApiVersion("2.0")] 就完事。路由和 Action 层级的版本感知要一致。
- Controller 上叠加多个
[ApiVersion]是 OK 的,但每个对应版本都得有匹配的路由入口,比如[Route("api/v{version:apiVersion}/users")] - 如果某个 Action 只适用于 v2(比如新增字段),要加
[MapToApiVersion("2.0")],否则 v1 请求也可能命中它 - 不要在 Action 参数里再写
[FromQuery] string version或[FromHeader] string api_version—— 这会绕过框架的版本协商,导致过滤器、日志、监控无法感知真实版本 - 启用
Deprecated = true(如[ApiVersion("1.0", Deprecated = true)])后,ReportApiVersions才会在响应头中暴露api-deprecated-versions
最易被忽略的一点:版本控制不是“加几个特性就完事”,它是贯穿路由、模型绑定、授权、日志、OpenAPI 文档的全链路能力。一旦某处(比如自定义 IActionConstraint 或中间件)没适配 ApiVersion 上下文,版本就会在那个环节断掉。


















