9

我正在寻找一种在 Swagger 文档中以可配置的方式使用 SwashBuckle 显示/隐藏 WebAPI 路由的方法。添加[ApiExplorerSettings(IgnoreApi = true)]确实会隐藏路线,但每次我想要更改时都需要重新编译。

我已经研究过创建一个IOperationFilter以使用我定义的自定义属性。这样我可以用 a 装饰路线[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并扫描它?

4

1 回答 1

6

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

与其使用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 页面上有一些问题帖子,建议将每个 HTTP 动词设置为 null swaggerDoc.pathApply我发现这会破坏很多像 AutoRest 这样的自动代码生成器,所以我只是简单地删除了整个路径。(看起来也更简洁)

于 2016-03-24T16:27:25.727 回答