Документация Swagger для веб-API2 при использовании атрибутов маршрута и параметров запроса

У меня есть простой проект веб-API2, который использует чванство для документации.

Учитывая простую конечную точку GET, которая использует параметры маршрута и параметры запроса, такие как:

[HttpGet]
[Route("api/v2/items/{itemid:int}")]
public IHttpActionResult Getv2(int itemId, [FromUri(Name ="")]DTOv1 request)
{
    return Ok();
}

public class DTOv1
{
    public DateTime? StartValue { get; set; }
}

Это дает следующую документацию: Правильная документация по Swagger

Однако я хотел бы иметь возможность указать все элементы в POCO. Такие как:

[HttpGet]
[Route("api/v3/items/{itemid:int}")]
public IHttpActionResult Getv3([FromUri(Name ="")]DTOv2 request)
{
    return Ok();
} 

public class DTOv2
{
    public int ItemId { get; set; }
    public DateTime? StartValue { get; set; }
}

Это дает следующую неправильную документацию: Неверная документация Swagger

Эта конечная точка GET работает так же, как и первый пример, но, как вы можете видеть, документация не работает, и попытка сделать пример не сработает. Можно ли настроить swagger так, чтобы это было задокументировано так же, как в первом примере, в идеале на основе соглашения?

Swagger просто использует настройку по умолчанию:

GlobalConfiguration.Configuration
    .EnableSwagger(c =>
        {
            c.SingleApiVersion("v1", "TestSwagger");
            c.PrettyPrint();
        })
    .EnableSwaggerUi(c =>
        {
        });

РЕДАКТИРОВАТЬ:

Благодаря ответу о добавлении фильтров я написал следующий фильтр операции, который работает в нашем случае использования для управления параметрами:

private class OperationFilter : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        if (apiDescription.HttpMethod.Method == "GET")
        {
            var pathParams = operation.parameters.Where(x => x.@in == "path");

            var toRemoveItems = new List<Parameter>();
            foreach(var pathParam in pathParams)
            {
                toRemoveItems.AddRange(operation
                    .parameters
                    .Where(x => x.@in != "path" && x.name.EndsWith(pathParam.name)));                     
            }

            foreach(var toRemove in toRemoveItems)
            {
                operation.parameters.Remove(toRemove);
            }
        }
    }
}

person Paul Wild    schedule 15.01.2018    source источник
comment
Если вы хотите указать все элементы в POCO, их не должно быть на маршруте...   -  person Helder Sepulveda    schedule 16.01.2018
comment
я мог видеть, что это правда, но что было бы рассуждением к этому. кроме того, что это плохо работает с генерацией документа, конечная точка работает правильно.   -  person Paul Wild    schedule 16.01.2018
comment
Если вы хотите изменить правила, вы можете использовать фильтр документов (IDocumentFilter), который даст вам 100% контроль над окончательным swagger.json, но имейте в виду, что вы можете получить что-то, что не соответствует OAS 2.0.   -  person Helder Sepulveda    schedule 16.01.2018
comment
Одна вещь. Атрибут маршрута чувствителен к регистру при поиске по имени объекта. поэтому [Route("api/v3/items/{itemid:int}")] должно быть [Route("api/v3/items/{ItemId}")]. Это, по крайней мере, устанавливает параметр как параметр пути   -  person Paul Wild    schedule 17.01.2018


Ответы (1)


Следуя моему предложению из комментариев об использовании IDocumentFilter, вот отправная точка:

    private class RouteTestDocumentFilter : IDocumentFilter
    {
        const string PATH = "/api/RouteTest/test/{itemid}";

        public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry s, IApiExplorer a)
        {
            if (swaggerDoc.paths != null && swaggerDoc.paths.ContainsKey(PATH))
            {
                var get = swaggerDoc.paths[PATH].get;
                if (get != null)
                {
                    get.parameters.RemoveAt(0);
                    get.parameters[0].@in = "path";
                    get.parameters[0].required = true;

                    foreach (var param in get.parameters)
                    {
                        int pos = param.name.IndexOf('.');
                        if (pos > 0)
                            param.name = param.name.Substring(pos + 1);
                    }
                }
            }
        }
    }

Подробнее см. в моей фиксации:
https://github.com/heldersepu/SwashbuckleTest/commit/38a31e0ee700faf91cc38d005ae1c5f4bec3e1f3

Вот как это выглядит в пользовательском интерфейсе:
http://swashbuckletest.azurewebsites.net/swagger/ui/index?filter=RouteTest#/RouteTest/RouteTest_Get

person Helder Sepulveda    schedule 16.01.2018
comment
Благодаря этому сообщению я рассмотрел использование фильтра операций для запросов GET, поиск всех параметров пути и последующее удаление параметров запроса с тем же именем. Кажется, это помогает и достаточно универсально для моего варианта использования в разных конечных точках. - person Paul Wild; 17.01.2018
comment
Я все еще чувствую, что это обходной путь в ограничении поколения swashbuckle. Я опубликую код, который я написал для всех, кто заинтересован - person Paul Wild; 17.01.2018