如何让无ApiVersion属性的接口始终生成默认版本Swagger文档?
问题:无ApiVersion属性的接口无法在混合版本控制器中生成默认版本Swagger文档
我在使用Asp.Versioning.Mvc.ApiExplorer库构建带版本的Swagger文档时遇到了问题:已经配置了Operation Filter,指定默认Api版本为1.0并开启了AssumeDefaultVersionWhenUnspecified,但当控制器中同时存在带ApiVersion属性和不带该属性的接口时,不带属性的接口不会生成默认版本(1.0)的Swagger文档——只有当控制器里全是无属性接口时,才会生成默认版本文档。我需要让无ApiVersion属性的接口始终生成默认版本的Swagger文档。
相关代码
Operation Filter实现
public void Apply(OpenApiOperation operation, OperationFilterContext context) { var apiDescription = context.ApiDescription; operation.Deprecated |= apiDescription.IsDeprecated(); foreach (var responseType in context.ApiDescription.SupportedResponseTypes) { var responseKey = responseType.IsDefaultResponse ? "default" : responseType.StatusCode.ToString(); var response = operation.Responses[responseKey]; foreach (var contentType in response.Content.Keys) { if (!responseType.ApiResponseFormats.Any(x => x.MediaType == contentType)) { response.Content.Remove(contentType); } } } if (operation.Parameters == null) { return; } foreach (var parameter in operation.Parameters) { var description = apiDescription.ParameterDescriptions .First(p => p.Name == parameter.Name); parameter.Description ??= description.ModelMetadata?.Description; if (parameter.Schema.Default == null && description.DefaultValue != null) { var json = JsonSerializer.Serialize( description.DefaultValue, description.ModelMetadata.ModelType); parameter.Schema.Default = OpenApiAnyFactory.CreateFromJson(json); } parameter.Required |= description.IsRequired; } }
测试控制器代码
[ApiController] [ApiExplorerSettings(GroupName = "Version")] [Route("version")] public class VersionController : ControllerBase { /// <summary> /// 测试接口(需要生成默认版本1.0的文档,但目前未生成) /// </summary> /// <response code="200">请求成功</response> [HttpGet] public async Task<IActionResult> Version1Get() { return Ok("version1.0 response"); } /// <summary> /// 测试1.2版本接口 /// </summary> /// <response code="200">请求成功</response> [HttpGet] [ApiVersion(1.2)] public async Task<IActionResult> Version2Get() { return Ok("version1.2 response"); } }
版本配置代码
{ options.ApiVersionReader = new HeaderApiVersionReader("x-ms-version"); options.DefaultApiVersion = new ApiVersion(1, 0); options.ReportApiVersions = true; options.AssumeDefaultVersionWhenUnspecified = true; }).AddMvc().AddApiExplorer( options => { options.GroupNameFormat = "VV"; options.FormatGroupName = (group, version) => $"{group} - {version}"; options.DefaultApiVersion = new ApiVersion(1, 0); options.AssumeDefaultVersionWhenUnspecified = true; } );
解决方案
这个问题的核心原因是:当控制器中存在带ApiVersion属性的接口时,Asp.Versioning会默认认为该控制器下所有接口都需要显式指定版本,忽略了全局的AssumeDefaultVersionWhenUnspecified配置。以下是两种可行的解决方式:
方法1:控制器级别显式声明支持的版本(官方推荐)
给控制器添加默认版本的ApiVersion属性,并开启AllowMultipleVersions,让无属性的接口自动继承默认版本:
[ApiController] [ApiExplorerSettings(GroupName = "Version")] [Route("version")] [ApiVersion(1.0)] // 显式声明默认版本 [ApiVersion(1.2)] // 声明已存在的1.2版本 [AllowMultipleVersions] // 允许控制器下存在多版本接口 public class VersionController : ControllerBase { // 无ApiVersion属性的接口会自动归到1.0版本 [HttpGet] public async Task<IActionResult> Version1Get() { return Ok("version1.0 response"); } [HttpGet] [ApiVersion(1.2)] public async Task<IActionResult> Version2Get() { return Ok("version1.2 response"); } }
方法2:自定义OperationFilter补全版本信息
如果不想修改控制器代码,可以通过自定义Filter为无版本属性的接口手动指定默认版本:
public class DefaultVersionOperationFilter : IOperationFilter { private readonly ApiVersion _defaultVersion; public DefaultVersionOperationFilter(ApiVersion defaultVersion) { _defaultVersion = defaultVersion; } public void Apply(OpenApiOperation operation, OperationFilterContext context) { var apiDescription = context.ApiDescription; // 检查接口是否未关联任何版本 if (!apiDescription.ApiVersionProperties.IsApiVersionNeutral && apiDescription.ApiVersionProperties.ApiVersion == null) { // 手动设置默认版本 apiDescription.ApiVersionProperties.ApiVersion = _defaultVersion; // 更新Swagger分组名称 apiDescription.GroupName = $"Version - {_defaultVersion.ToString()}"; } // 执行原有OperationFilter逻辑 var originalFilter = new YourOriginalOperationFilter(); originalFilter.Apply(operation, context); } }
然后在Swagger配置中注册该Filter:
services.AddSwaggerGen(options => { options.OperationFilter<DefaultVersionOperationFilter>(new ApiVersion(1, 0)); });
内容的提问来源于stack exchange,提问作者Vorasoda
相关产品推荐
相关产品推荐

