Удалить маршрут с IOperationFilter в SwashBuckle

Я ищу способ показать /скрыть маршруты WebAPI в документации Swagger, используя настраиваемый способ SwashBuckle. Добавление [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 и сканировать через него?

7 голосов | спросил LukeP 24 MaramThu, 24 Mar 2016 02:27:27 +03002016-03-24T02:27:27+03:0002 2016, 02:27:27

1 ответ


0

Кто-то ранее опубликовал ответ и сказал, что отправит код, как только получит шанс. Они по какой-то причине удалили свой ответ, но это помогло мне найти лучшее решение.

Вместо использования 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: На странице GitHub есть несколько сообщений о проблемах для SwashBuckle, которые рекомендуют устанавливать для каждого из глаголов HTTP значение null в swaggerDoc.path в Apply. Я обнаружил, что это сломало многие авто генераторы кода, такие как AutoRest, поэтому я просто удаляю путь в целом. (Это тоже выглядит более лаконично)

ответил LukeP 24 MarpmThu, 24 Mar 2016 19:27:25 +03002016-03-24T19:27:25+03:0007 2016, 19:27:25

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132