问题描述
我正在寻找一种在 Swagger 文档中以可配置的方式使用 SwashBuckle 显示/隐藏 WebAPI 路由的方法.添加 [ApiExplorerSettings(IgnoreApi = true)]
确实会隐藏路由,但每次我想要更改时都需要重新编译.
I am looking for a way to show/hide WebAPI routes in the Swagger documentation using SwashBuckle in a configurable way. Adding [ApiExplorerSettings(IgnoreApi = true)]
will indeed hide the routes but I'd need to recompile every time I want that to change.
我已经研究过创建一个 IOOperationFilter
以使用我定义的自定义属性.这样我就可以用 [SwaggerTag("MobileOnly")]
装饰路线并检查 web.config 或其他内容以查看是否应显示路线.属性定义如下:
I have looked into creating an IOperationFilter
to work with a custom Attribute that I defined. That way I can decorate the routes with a [SwaggerTag("MobileOnly")]
and check the web.config or something to see if the route should be shown. The Attribute is defined as such:
public class SwaggerTagAttribute : Attribute
{
public string[] Tags { get; private set; }
public SwaggerTagAttribute(params string[] tags)
{
this.Tags = tags;
}
}
这里定义了检测属性的IOperationFilter
和移除路径的IDocumentFilter
:
The IOperationFilter
that detects the attribute is defined and the IDocumentFilter
that removes the path is defined here:
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>();
});
我觉得当我更早地访问它时,标记某些东西以便稍后删除它是低效且hacky的.有什么方法可以让我从 IOperationFilter.Apply
中删除路由,而不是等待 IDocumentFilter
并扫描它?
I feel that this is inefficient and hacky to tag something for removal later when I have access to it earlier. Is there any way that I just remove the route from the within IOperationFilter.Apply
rather than wait for the IDocumentFilter
and scan through it?
推荐答案
之前有人发布了一个答案,并说一旦有机会他们就会发布代码.他们出于某种原因删除了他们的答案,但这让我找到了更好的解决方案.
Someone had posted an answer earlier and said they'd post code once they got a chance. They have deleted their answer for some reason but it got me to a better solution.
而不是使用 IOperationFilter
标记路由,然后 IDocumentFilter
稍后删除路由,您可以使用 IDocumentFilter
查找自定义属性并一口气将其删除.代码如下:
Rather than using IOperationFilter
to tag the route and then IDocumentFilter
to remove the route later you can just use IDocumentFilter
to find the custom attribute and remove it in one fell swoop. The code is below:
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>();
});
然后像这样装饰一条路线:
Then just decorate a route like so:
[SwaggerTag("MobileOnly")]
public IHttpActionResult SendTest(Guid userId)
{
return OK();
}
Edit:
SwashBuckle 的 GitHub 页面上有一些问题帖子,建议在 Apply 中的
swaggerDoc.path
上将每个 HTTP 动词设置为 null代码>.我发现这会破坏很多像 AutoRest 这样的自动代码生成器,所以我只是简单地删除了整个路径.(看起来也更简洁了)
There are some issue posts on the GitHub page for SwashBuckle that recommend setting each of the HTTP verbs to null on the
swaggerDoc.path
in Apply
. I found this to break a lot of auto code generators like AutoRest so I am simply removing the path as a whole. (It looks more succinct too)
这篇关于在 SwashBuckle 中使用 IOperationFilter 删除路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!