.Net Core 5.0应用Swagger版本配置异常:路由格式不符、版本切换未过滤端点
版本化Swagger配置修复方案
你遇到的两个异常都来自现有配置和逻辑的匹配缺陷,逐点调整即可正常运行:
问题a:Swagger路由版本显示为/api/v1/... 而非预期的/api/v1.0/...
- 根因是
AddVersionedApiExplorer的版本格式化规则不匹配:设置的o.GroupNameFormat = "'v'VVV"中,VVV是简化版本格式,会把1.0、2.0这类次版本为0的版本截断为纯主版本数字,最终渲染为v1而非v1.0。 - 修复方式:将格式化规则替换为可保留完整次版本号的配置:
o.GroupNameFormat = "'v'VVV[.FFF]",该规则会完整渲染带小数点的版本值,不会自动截断版本号。 - 补充:你之前注释掉的两个Swagger过滤器可以直接启用,能解决路由版本参数残留的问题,对应的实现代码如下:
把之前注释的两行过滤器配置打开即可:// 从Swagger请求参数列表中移除路由自带的version占位符参数 public class SwaggerRemoveVersionFromParameter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { var versionParam = operation.Parameters.FirstOrDefault(p => p.Name == "version"); if (versionParam != null) operation.Parameters.Remove(versionParam); } } // 把路由占位符中的{version}替换为当前文档对应的实际版本值 public class SwaggerReplaceVersionWithExactValueInPath : IDocumentFilter { public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { var allPaths = swaggerDoc.Paths.Keys.ToList(); foreach (var oldPath in allPaths) { var newPath = oldPath.Replace("v{version}", $"v{context.ApiDescription.GroupName}"); swaggerDoc.Paths[newPath] = swaggerDoc.Paths[oldPath]; swaggerDoc.Paths.Remove(oldPath); } } }c.OperationFilter<SwaggerRemoveVersionFromParameter>(); c.DocumentFilter<SwaggerReplaceVersionWithExactValueInPath>();
问题b:Swagger下拉切换版本时,所有端点混合展示,无法按版本过滤
- 根因是自定义的
DocInclusionPredicate匹配逻辑存在缺陷:
现有逻辑只提取了控制器类上标注的ApiVersion属性,完全没有匹配Action方法自身的版本标注。加上你的控制器同时标注了v1.0、v2.0两个版本,所有挂在这个控制器下的Action不管自身标注了什么版本,都会被判定为同时属于两个版本的端点,最终所有端点都会出现在每个版本的展示列表里。 - 修复方式:重写
DocInclusionPredicate的匹配逻辑,同时识别控制器级、Action级的版本标注,并且匹配端点实际归属的API版本:c.DocInclusionPredicate((docName, apiDesc) => { if (!apiDesc.TryGetMethodInfo(out MethodInfo methodInfo)) return false; // 同时收集控制器和Action上标注的所有API版本 var allDefinedVersions = methodInfo.DeclaringType.GetCustomAttributes(true) .Concat(methodInfo.GetCustomAttributes(true)) .OfType<ApiVersionAttribute>() .SelectMany(attr => attr.Versions); // 获取当前端点实际归属的API版本 var endpointApiVersion = apiDesc.GetApiVersion(); if (endpointApiVersion == null) return false; // 匹配文档名和端点所属版本 return allDefinedVersions.Any(v => $"v{v}" == docName) && $"v{endpointApiVersion}" == docName; }); - 额外注意:当前配置开启了
AssumeDefaultVersionWhenUnspecified = true,这个规则会让没有显式标注版本的Action自动归类到默认的v1.0版本,也是你看到所有标了v2.0的端点全跑到v1.0分组下的重要诱因。如果所有Action都已经显式标注了版本属性,建议将该配置关闭,避免未标注属性的端点被错误归类到默认版本下。
内容的提问来源于stack exchange,提问作者Mark and Mollie
相关产品推荐
相关产品推荐

