Подтвердить что ты не робот

Документация Swagger UI Web Api Представляем перечисления как строки?

Есть ли способ показать все перечисления как их строковое значение в swagger вместо их значения int?

Я хочу, чтобы иметь возможность отправлять POST-действия и помещать перечисления в соответствии со своим строковым значением, не просматривая каждый раз перечисление.

Я попробовал DescribeAllEnumsAsStrings, но затем сервер получает строки вместо значения перечисления, которое не то, что мы ищем.

Кто-нибудь решил это?

Edit:

public class Letter 
{
    [Required]
    public string Content {get; set;}

    [Required]
    [EnumDataType(typeof(Priority))]
    public Priority Priority {get; set;}
}


public class LettersController : ApiController
{
    [HttpPost]
    public IHttpActionResult SendLetter(Letter letter)
    {
        // Validation not passing when using DescribeEnumsAsStrings
        if (!ModelState.IsValid)
            return BadRequest("Not valid")

        ..
    }

    // In the documentation for this request I want to see the string values of the enum before submitting: Low, Medium, High. Instead of 0, 1, 2
    [HttpGet]
    public IHttpActionResult GetByPriority (Priority priority)
    {

    }
}


public enum Priority
{
    Low, 
    Medium,
    High
}
4b9b3361

Ответ 1

Из документов:

httpConfiguration
    .EnableSwagger(c => 
        {
            c.SingleApiVersion("v1", "A title for your API");

            c.DescribeAllEnumsAsStrings(); // this will do the trick
        });

Кроме того, если вы хотите, чтобы это поведение выполнялось только для определенного типа и свойства, используйте StringEnumConverter:

public class Letter 
{
    [Required]
    public string Content {get; set;}

    [Required]
    [EnumDataType(typeof(Priority))]
    [JsonConverter(typeof(StringEnumConverter))]
    public Priority Priority {get; set;}
}

Ответ 2

Поэтому я думаю, что у меня похожая проблема. Я ищу swagger для генерации перечислений вместе с int → string mapping. API должен принять int. Swagger-ui менее важен, я действительно хочу генерацию кода с "реальным" перечислением на другой стороне (в этом случае приложения для Android используют модификацию).

Так что из моих исследований это в конечном счете кажется ограничением спецификации OpenAPI, которую использует Swagger. Невозможно указать имена и номера для перечислений.

Лучшая проблема, за которой я обнаружил, - https://github.com/OAI/OpenAPI-Specification/issues/681, которая выглядит как "возможно, скоро", но тогда Swagger придется обновить, а в моем случае Swashbuckle как Что ж.

На данный момент мой обходной путь заключается в реализации фильтра документов, который ищет перечисления и заполняет соответствующее описание содержимым перечисления.

        GlobalConfiguration.Configuration
            .EnableSwagger(c =>
                {
                    c.DocumentFilter<SwaggerAddEnumDescriptions>();

                    //disable this
                    //c.DescribeAllEnumsAsStrings()

SwaggerAddEnumDescriptions.cs:

using System;
using System.Web.Http.Description;
using Swashbuckle.Swagger;
using System.Collections.Generic;

public class SwaggerAddEnumDescriptions : IDocumentFilter
{
    public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
    {
        // add enum descriptions to result models
        foreach (KeyValuePair<string, Schema> schemaDictionaryItem in swaggerDoc.definitions)
        {
            Schema schema = schemaDictionaryItem.Value;
            foreach (KeyValuePair<string, Schema> propertyDictionaryItem in schema.properties)
            {
                Schema property = propertyDictionaryItem.Value;
                IList<object> propertyEnums = [email protected];
                if (propertyEnums != null && propertyEnums.Count > 0)
                {
                    property.description += DescribeEnum(propertyEnums);
                }
            }
        }

        // add enum descriptions to input parameters
        if (swaggerDoc.paths.Count > 0)
        {
            foreach (PathItem pathItem in swaggerDoc.paths.Values)
            {
                DescribeEnumParameters(pathItem.parameters);

                // head, patch, options, delete left out
                List<Operation> possibleParameterisedOperations = new List<Operation> { pathItem.get, pathItem.post, pathItem.put };
                possibleParameterisedOperations.FindAll(x => x != null).ForEach(x => DescribeEnumParameters(x.parameters));
            }
        }
    }

    private void DescribeEnumParameters(IList<Parameter> parameters)
    {
        if (parameters != null)
        {
            foreach (Parameter param in parameters)
            {
                IList<object> paramEnums = [email protected];
                if (paramEnums != null && paramEnums.Count > 0)
                {
                    param.description += DescribeEnum(paramEnums);
                }
            }
        }
    }

    private string DescribeEnum(IList<object> enums)
    {
        List<string> enumDescriptions = new List<string>();
        foreach (object enumOption in enums)
        {
            enumDescriptions.Add(string.Format("{0} = {1}", (int)enumOption, Enum.GetName(enumOption.GetType(), enumOption)));
        }
        return string.Join(", ", enumDescriptions.ToArray());
    }

}

Это приводит к чему-то вроде следующего на вашем swagger-интерфейсе, так что вы, по крайней мере, можете "увидеть, что вы делаете": enter image description here

Ответ 3

Я хотел использовать ответ rory_za в приложении .NET Core, но мне пришлось немного его изменить, чтобы он работал. Вот реализация, которую я придумал для .NET Core.

Я также изменил его, чтобы он не предполагал, что основным типом является int, и использую новые строки между значениями для облегчения чтения.

/// <summary>
/// Add enum value descriptions to Swagger
/// </summary>
public class EnumDocumentFilter : IDocumentFilter {
    /// <inheritdoc />
    public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context) {
        // add enum descriptions to result models
        foreach (var schemaDictionaryItem in swaggerDoc.Definitions) {
            var schema = schemaDictionaryItem.Value;
            foreach (var propertyDictionaryItem in schema.Properties) {
                var property = propertyDictionaryItem.Value;
                var propertyEnums = property.Enum;
                if (propertyEnums != null && propertyEnums.Count > 0) {
                    property.Description += DescribeEnum(propertyEnums);
                }
            }
        }

        if (swaggerDoc.Paths.Count <= 0) return;

        // add enum descriptions to input parameters
        foreach (var pathItem in swaggerDoc.Paths.Values) {
            DescribeEnumParameters(pathItem.Parameters);

            // head, patch, options, delete left out
            var possibleParameterisedOperations = new List<Operation> {pathItem.Get, pathItem.Post, pathItem.Put};
            possibleParameterisedOperations.FindAll(x => x != null)
                .ForEach(x => DescribeEnumParameters(x.Parameters));
        }
    }

    private static void DescribeEnumParameters(IList<IParameter> parameters) {
        if (parameters == null) return;

        foreach (var param in parameters) {
            if (param is NonBodyParameter nbParam && nbParam.Enum?.Any() == true) {
                param.Description += DescribeEnum(nbParam.Enum);
            } else if (param.Extensions.ContainsKey("enum") && param.Extensions["enum"] is IList<object> paramEnums &&
                paramEnums.Count > 0) {
                param.Description += DescribeEnum(paramEnums);
            }
        }
    }

    private static string DescribeEnum(IEnumerable<object> enums) {
        var enumDescriptions = new List<string>();
        Type type = null;
        foreach (var enumOption in enums) {
            if (type == null) type = enumOption.GetType();
            enumDescriptions.Add($"{Convert.ChangeType(enumOption, type.GetEnumUnderlyingType())} = {Enum.GetName(type, enumOption)}");
        }

        return $"{Environment.NewLine}{string.Join(Environment.NewLine, enumDescriptions)}";
    }
}

Затем добавьте это в ваш метод ConfigureServices в Startup.cs:

c.DocumentFilter<EnumDocumentFilter>();

Ответ 4

Для ASP.Net Core просто сделайте это в Startup.cs/ConfigureServices():

services
    .AddMvc(...)
    .AddJsonOptions(options => options.SerializerSettings.Converters.Add(new StringEnumConverter()));

Подход DescribeAllEnumsAsStrings(), который все остальные, похоже, дают, не работает для меня, потому что тогда, как сказал OP, сервер получает строки и ожидает целочисленные значения. Чтобы сервер мог ожидать строки, вам нужно добавить StringEnumConverter в SerializerSettings, как описано выше, плюс вы можете полностью исключить DescribeAllEnumsAsStrings().

Ответ 5

Я только что сделал это, и он отлично работает!

Startup.cs

services.AddSwaggerGen(c => {
  c.DescribeAllEnumsAsStrings();
});

Model.cs

public enum ColumnType {
  DATE = 0
}

swagger.json

type: {
  enum: ["DATE"],
  type: "string"
}

Я надеюсь, что это поможет вам, как это помогло мне!

Ответ 6

написать код внутри Startup.cs

services.AddSwaggerGen(c => {
      c.DescribeAllEnumsAsStrings();
    });

Ответ 7

.Net Core 3.0

   using Newtonsoft.Json.Converters;

 services
    .AddMvc(options =>
    {
     options.EnableEndpointRouting = false;
     })
    .AddNewtonsoftJson(options => options.SerializerSettings.Converters.Add(new StringEnumConverter()))

Ответ 8

С ядром asp.net 3

using System.Text.Json.Serialization;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
         services.AddControllers().AddJsonOptions(options =>
             options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));

Но похоже, что версия Swashbuckle 5.0.0-rc4 не готова это поддерживать. Поэтому нам нужно использовать параметр (не рекомендуется) в конфигурационном файле Swashbuckle, пока он не будет поддерживать и отображать его как библиотеку Newtonsoft.

public void ConfigureServices(IServiceCollection services)
{ 
      services.AddSwaggerGen(c =>
      {
            c.DescribeAllEnumsAsStrings();

Разница между этим ответом и другими ответами заключается в использовании только библиотеки Microsoft JSON вместо Newtonsoft.