使用SwashBuckle中的IOperationFilter删除路线
我正在寻找一种使用SwashBuckle以可配置的方式在Swagger文档中显示/隐藏WebAPI路由的方法。 添加[ApiExplorerSettings(IgnoreApi = true)]
确实会隐藏路线,但每次我想要改变时都需要重新编译。
我已经研究过创建一个IOperationFilter
来处理我定义的一个自定义属性。 这样我就可以用[SwaggerTag("MobileOnly")]
装饰路线,并检查web.config或其他东西,看看是否应该显示路线。 属性定义如下:
public class SwaggerTagAttribute : Attribute
{
public string[] Tags { get; private set; }
public SwaggerTagAttribute(params string[] tags)
{
this.Tags = tags;
}
}
定义检测属性的IOperationFilter
,并在此处定义删除路径的IDocumentFilter
:
public class RemoveTaggedOperationsFilter : IOperationFilter, IDocumentFilter
{
private List<string> TagsToHide;
public RemoveTaggedOperationsFilter()
{
TagsToHide = ConfigurationManager.AppSettings["TagsToHide"].Split(',').ToList();
}
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
var tags = apiDescription.ActionDescriptor
.GetCustomAttributes<SwaggerTagAttribute>()
.Select(t => t.Tags)
.FirstOrDefault();
if (tags != null && TagsToHide.Intersect(tags).Any())
{
operation.tags = new List<string> {"Remove Me "};
}
}
public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
{
foreach (var value in swaggerDoc.paths.Values)
{
if (value.post != null && value.post.tags.Contains("Remove Me"))
value.post = null;
if (value.get != null && value.get.tags.Contains("Remove Me"))
value.get = null;
if (value.put != null && value.put.tags.Contains("Remove Me"))
value.put = null;
if (value.delete != null && value.delete.tags.Contains("Remove Me"))
value.delete = null;
}
}
}
并注册为:
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.OperationFilter<RemoveTaggedOperationsFilter>();
c.DocumentFilter<RemoveTaggedOperationsFilter>();
});
我觉得这样做效率低下,而且在我稍后访问它时会标记某些要删除的内容。 有没有什么办法可以从IOperationFilter.Apply
删除路由,而不是等待IDocumentFilter
并扫描它?
有人早些时候发布了答案,并表示一旦有机会,他们会发布代码。 他们由于某种原因删除了他们的答案,但它让我得到了更好的解决方案。
而不是使用IOperationFilter
标记的路线,然后IDocumentFilter
删除路径后,你可以只使用IDocumentFilter
找到自定义属性,并一举将其删除。 代码如下:
public class HideTaggedOperationsFilter : IDocumentFilter
{
private List<string> TagsToHide;
public HideTaggedOperationsFilter()
{
TagsToHide = ConfigurationManager.AppSettings["TagsToHide"].Split(',').ToList();
}
public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
{
if (_tagsToHide == null) return;
foreach (var apiDescription in apiExplorer.ApiDescriptions)
{
var tags = apiDescription.ActionDescriptor
.GetCustomAttributes<SwaggerTagAttribute>()
.Select(t => t.Tags)
.FirstOrDefault();
if (tags == null || !_tagsToHide.Intersect(tags).Any())
continue;
var route = "/" + apiDescription.Route.RouteTemplate.TrimEnd('/');
swaggerDoc.paths.Remove(route);
}
}
}
public class SwaggerTagAttribute : Attribute
{
public string[] Tags { get; }
public SwaggerTagAttribute(params string[] tags)
{
this.Tags = tags;
}
}
注册IDocumentFilter
:
GlobalConfiguration.Configuration.EnableSwagger(c =>
{
...
c.DocumentFilter<HideTaggedOperationsFilter>();
});
然后,只需修饰一下这样的路线:
[SwaggerTag("MobileOnly")]
public IHttpActionResult SendTest(Guid userId)
{
return OK();
}
Edit:
在SwashBuckle的GitHub页面上有一些问题帖子,建议在Apply
中将swaggerDoc.path
中的每个HTTP动词设置为null。 我发现这打破了很多像AutoRest这样的自动代码生成器,所以我只是简单地删除整个路径。 (它看起来更简洁)
上一篇: Remove a route with IOperationFilter in SwashBuckle
下一篇: Is there a way to make git automatically retry commands if index.lock exists?