【问题标题】:Remove a route with IOperationFilter in SwashBuckle在 SwashBuckle 中使用 IOperationFilter 删除路由
【发布时间】:2016-03-23 23:27:27
【问题描述】:

我正在寻找一种在 Swagger 文档中以可配置的方式使用 SwashBuckle 显示/隐藏 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>();
                });

我觉得当我更早地访问它时标记某些东西以便稍后删除它是低效和hacky的。有什么方法可以让我从IOperationFilter.Apply 中删除路由,而不是等待IDocumentFilter 并扫描它?

【问题讨论】:

    标签: c# asp.net-web-api swagger custom-attributes swashbuckle


    【解决方案1】:

    之前有人发布了一个答案,并说一旦有机会他们就会发布代码。他们出于某种原因删除了他们的答案,但这让我找到了更好的解决方案。

    而不是使用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 这样的自动代码生成器,所以我只是简单地删除了整个路径。 (看起来也更简洁了)

    【讨论】:

    • 如果你有不同动词的相同路线,但只想禁用一些,这种方法将不起作用。即拥有 GET /transcations 和 POST /transactions,当只有 1 个操作方法被自定义属性修饰时,两者都会被删除。您还需要考虑 http 方法。
    • @ParaJaco 这是一个很好的观点。扩展它以考虑 HTTP 动词可能不会太难。
    • 我可以装饰整个控制器吗?
    • 好问题。我不是 100% 确定,因为我没有尝试过。随意尝试一下,让我知道。如果它不起作用,也许我可以看到需要做些什么来扩展它以支持控制器属性装饰。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-24
    • 2010-12-15
    • 2012-05-03
    • 1970-01-01
    • 2017-12-16
    • 2016-03-25
    相关资源
    最近更新 更多