我正在使用面向公众的API,使用Swashbuckle.AspNetCore
和ReDoc
进行文档编写,并使用Microsoft.AspNetCore.Mvc.Versioning
使用属性对控制器进行版本控制。
我们希望有一个醒目的文档来显示我们端点的所有最新版本,以使初次使用该API的人们更容易选择正确的版本。
我当前的尝试是创建一个'v0'并将该版本应用于所有最新版本的控制器。然后,我使用操作过滤器将“ v0”替换为最新版本:
public class LatestVersionOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var version = (context.MethodInfo.GetCustomAttributes<ApiVersionAttribute>()
.Union(context.MethodInfo.DeclaringType.GetCustomAttributes<ApiVersionAttribute>())
.SelectMany(x => x.Versions)
.OrderByDescending(x => x.MajorVersion))
.FirstOrDefault(x => x.MajorVersion != 0);
if (version != null && context.ApiDescription.RelativePath.Contains("v0"))
{
context.ApiDescription.RelativePath = context.ApiDescription.RelativePath
.Replace("v0", $"v{version.MajorVersion}");
}
}
}
这在大多数情况下都有效,但有时似乎没有效果,您最终得到了一堆带有'v0'的URL。过滤器运行了,但似乎并未反映在结果中招摇的文件。
是否有更好的方法来实现我们的目标?我尝试使用DocInclusionPredicate
编写内容,但似乎无法获得想要的内容。
经过更多挖掘之后,我发现了这个旧问题:https://github.com/domaindrivendev/Swashbuckle/issues/361
我之前尝试过文档过滤器,但是感觉像走错了路。看到这个问题,我又走了一步,下面的内容正在为我们工作:
public class LatestVersionDocumentFilter : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
foreach (var path in swaggerDoc.Paths.ToList())
{
if (!path.Key.Contains("v0"))
{
continue;
}
var apiDescription = context.ApiDescriptions.FirstOrDefault(x => x.RelativePath == path.Key.TrimStart('/'));
if (apiDescription != null && apiDescription.TryGetMethodInfo(out var methodInfo))
{
var latestVersion = methodInfo.GetCustomAttributes<ApiVersionAttribute>()
.Union(methodInfo.DeclaringType.GetCustomAttributes<ApiVersionAttribute>())
.SelectMany(x => x.Versions)
.OrderByDescending(x => x.MajorVersion)
.FirstOrDefault(x => x.MajorVersion != 0);
if (latestVersion != null)
{
swaggerDoc.Paths.Remove(path.Key);
var latestUrl = path.Key.Replace("/v0/", $"/v{latestVersion.MajorVersion}/");
swaggerDoc.Paths.Add(latestUrl, path.Value);
}
}
}
}
}