Documentação do Swagger UI Web Api Apresentar enums como strings?

107

Existe uma maneira de exibir todos os enums como seu valor de string em swagger em vez de seu valor int?

Quero ser capaz de enviar ações POST e colocar enums de acordo com seu valor de string sem ter que olhar para enum todas as vezes.

Tentei, DescribeAllEnumsAsStringsmas o servidor recebe strings em vez do valor enum, que não é o que estamos procurando.

Alguém resolveu isso?

Editar:

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
}

fonte
1
Você deseja que o esquema descreva o valor como uma string, mas depois poste um inteiro no servidor? JSON.net lidará bem com ambos os valores, então a versão somente inteiro é um requisito definitivo? Eu não acho que o Swagger oferece suporte a um tipo de enum com a string e o valor inteiro.
Hux,
1
Seu comportamento esperado não está claro. Você pode explicar melhor o que deseja que a IU do Swagger exiba e o que deseja POST / PUT em sua API da Web com exemplos?
Federico Dipuma
Além disso, se eu tiver métodos GET que levam enum no url, quero que o esquema os descreva como strings na lista suspensa de valores sugeridos
Por que a validação de inteiro falha? O tipo deve ser um enum no modelo e o formatador de mídia json manipularia corretamente uma string ou int. Se você atualizar a pergunta com um exemplo, isso nos ajudará a entender por que a validação está falhando.
Hux,
4
Se for um enum de sinalizadores, ele deve ser numérico, a menos que você tenha valores enum definidos para cada combinação possível de sinalizadores. É uma loucura que o swagger não exibe AMBOS o nome e o valor de cada enum e, em vez disso, exibe apenas o número (inútil) ou apenas os nomes (novamente, inútil para sinalizadores que devem ser especificados como números).
Triynko

Respostas:

188

Dos documentos :

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

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

Além disso, se você deseja esse comportamento apenas em um determinado tipo e propriedade, use StringEnumConverter:

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

    [Required]
    [EnumDataType(typeof(Priority))]
    [JsonConverter(typeof(StringEnumConverter))]
    public Priority Priority {get; set;}
}
Xavero
fonte
5
isso não funciona para mim. [EnumDataType (typeof (Priority))] [JsonConverter (typeof (StringEnumConverter))]
Lineker
@NH. sim, usei newtonsoft.json
Lineker
@Lineker, poste seu erro como uma nova pergunta, seguindo este guia: stackoverflow.com/help/mcve
NH.
THX! Acho que também posso deixar seu comentário na fonte #thiswilldothetrick
Simon_Weaver
5
DescribeAllEnumsAsStringstrabalhou para propriedades de objeto e até mesmo parâmetros de consulta em ações do controlador. No entanto, usar EnumDataTypeAttributee JsonConverter(typeof(StringEnumConverter))não funcionou para mim.
bugged87 de
92

Para ASP.NET Core 3 com a biblioteca Microsoft JSON (System.Text.Json)

Em Startup.cs / ConfigureServices ():

services
    .AddControllersWithViews(...) // or AddControllers() in a Web API
    .AddJsonOptions(options => 
        options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));

Para ASP.NET Core 3 com a biblioteca Json.NET (Newtonsoft.Json)

Instale o Swashbuckle.AspNetCore.Newtonsoftpacote.

Em Startup.cs / ConfigureServices ():

services
    .AddControllersWithViews(...)
    .AddNewtonsoftJson(options => 
        options.SerializerSettings.Converters.Add(new StringEnumConverter()));
// order is vital, this *must* be called *after* AddNewtonsoftJson()
services.AddSwaggerGenNewtonsoftSupport();

Para ASP.NET Core 2

Em Startup.cs / ConfigureServices ():

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

Pre-ASP.NET Core

httpConfiguration
    .EnableSwagger(c => 
        {
            c.DescribeAllEnumsAsStrings();
        });
Lee Richardson
fonte
4
O problema de usar options.SerializerSettings.Converters.Add (new StringEnumConverter ())) é que você está mudando o json para todos os seus métodos, não apenas para Sawshbuckle.
Guillaume
Alguém tem uma solução para Azure Functions v2 e / ou v3?
Dan Friedman
@DanFriedman Considerando que o Swashbuckle não funciona com o Azure Functions, você está sem sorte.
Ian Kemp
@IanKemp Há suporte de terceiros com o AzureExtensions.Swashbucklepacote, mas como @DanFriedman, não consigo fazer o enum-to-string funcionar como esperado
wolfyuk
40

Então, acho que tenho um problema semelhante. Estou procurando swagger para gerar enums junto com o mapeamento de string int ->. A API deve aceitar o int. O swagger-ui importa menos, o que eu realmente quero é a geração de código com um enum "real" do outro lado (apps para Android usando retrofit neste caso).

Então, de acordo com minha pesquisa, isso parece ser um limite da especificação OpenAPI que o Swagger usa. Não é possível especificar nomes e números para enums.

O melhor problema que descobri para seguir é https://github.com/OAI/OpenAPI-Specification/issues/681 que parece um "talvez em breve", mas o Swagger teria que ser atualizado e, no meu caso, Swashbuckle como bem.

Por enquanto, minha solução alternativa foi implementar um filtro de documento que procura enums e preenche a descrição relevante com o conteúdo do enum.

        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 = property.@enum;
                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 = param.@enum;
                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());
    }

}

Isso resulta em algo como o seguinte em seu swagger-ui para que pelo menos você possa "ver o que está fazendo": insira a descrição da imagem aqui

Rory
fonte
1
1 Eu estava procurando adicionar descrições a enums (apenas para 'descrever enum'), nunca pensei nisso. Já tenho filtros diversos, mas estava procurando por algo mais 'orgânico', mas não há suporte. Bem, então, filtros completamente :)
NSGaga-principalmente-inativo
Obrigado! Usei isso em meu projeto, mas modifiquei para funcionar com o .NET Core. Eu adicionei minha implementação como uma resposta.
Gabriel Luci de
27

ASP.NET Core 3.1

Para gerar enums como strings usando Newtonsoft JSON, você deve adicionar explicitamente o suporte a Newtonsoft adicionando AddSwaggerGenNewtonsoftSupport()o seguinte:

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


services.AddSwaggerGen(...);
services.AddSwaggerGenNewtonsoftSupport(); //

Isso está disponível por meio de um novo pacote Swashbuckle.AspNetCore.Newtonsoft,. Parece que todo o resto funciona bem sem este pacote, exceto o suporte ao conversor de enum.

Roman Starkov
fonte
1
Isso ajuda a configurar essa convenção globalmente, mas se você precisar aplicá-la apenas a certos tipos de enums, você precisará ler este problema com atenção . TL; DR: Não é possível aplicar new StringEnumConverter () apenas à propriedade, mas você pode aplicá-lo a todo o tipo de enum.
A. Tretiakov
1
Suponho que, se estamos falando de pegadinhas, também não seja possível usar um conversor totalmente personalizado. O Swagger não executa os valores enum por meio do conversor personalizado; simplesmente reconhece StringEnumConvertercomo um caso especial.
Roman Starkov
22

Eu queria usar a resposta de rory_za em um aplicativo .NET Core, mas tive que modificá-la um pouco para que funcionasse. Aqui está a implementação que criei para o .NET Core.

Eu também mudei para que não presuma que o tipo subjacente seja int, e use novas linhas entre os valores para facilitar a leitura.

/// <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)}";
    }
}

Em seguida, adicione isso ao seu ConfigureServicesmétodo em Startup.cs:

c.DocumentFilter<EnumDocumentFilter>();
Gabriel luci
fonte
É possível remover o Enum: Array [6] que aparece abaixo?
Softlion
4
Ótima solução, mas as extensões DescribeEnumParametersestavam vazias no meu projeto. Tive que lançar o parampara NonBodyParametere verificar o enum lá:if (param is NonBodyParameter nbParam && nbParam.Enum?.Any() == true) { param.Description += DescribeEnum(nbParam.Enum); }
Rabban
No meu projeto Extensions está vazio também, usei a solução @Rabban.
Carlos Beppler
1
@Rabban Eu atualizei meu código para incluir isso. Você pode apenas verificar se eu coloquei no lugar certo? Eu não tive esse problema. Talvez uma versão mais recente tenha mudado as coisas.
Gabriel Luci
@GabrielLuci Confirmado e aprovado;)
Rabban
12

Com asp.net core 3

using System.Text.Json.Serialization;

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

Mas parece que a versão 5.0.0-rc4 do Swashbuckle não está pronta para suportar isso. Portanto, precisamos usar uma opção (obsoleta) no arquivo de configuração do Swashbuckle até que ela a suporte e reflita como a biblioteca Newtonsoft.

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

A diferença entre esta resposta e outras respostas é usar apenas a biblioteca JSON da Microsoft em vez de Newtonsoft.

Bashir Momen
fonte
Ei, @Bashir, há um problema de swachbuckle para controlar a falta desse suporte?
Bernard Vander Beken,
Olá @ bernard-vander-beken, Não informei isso, mas presumo que sim. É bom se pudermos encontrá-lo e adicioná-lo a este post para atualizações posteriores.
Bashir Momen
10

.NET CORE 3.1 e SWAGGER 5

se você precisar de uma solução simples para fazer enums seletivamente passados ​​como strings:

using System.Text.Json.Serialization;


[JsonConverter(typeof(JsonStringEnumConverter))]
public enum MyEnum
{
    A, B
}

Observe, usamos o System.Text.Json.Serializationnamespace, não o Newtonsoft.Json!

VeganHunter
fonte
Este funciona mostrando os valores adequados e também funciona ao converter os valores de volta para o enum. Observe que você precisa adicionar o pacote NuGet System.Text.Json.
MovGP0
É isso que eu estava procurando! Como preciso usar string apenas para enum único, DescribeAllEnumsAsStringsvou converter todos os enums para a string.
Nilay
9

se alguém estiver interessado, eu modifiquei o código para trabalhar com

.NET CORE 3 e Swagger V5

    public class SwaggerAddEnumDescriptions : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        // add enum descriptions to result models
        foreach (var property in swaggerDoc.Components.Schemas.Where(x => x.Value?.Enum?.Count > 0))
        {
            IList<IOpenApiAny> propertyEnums = property.Value.Enum;
            if (propertyEnums != null && propertyEnums.Count > 0)
            {
                property.Value.Description += DescribeEnum(propertyEnums, property.Key);
            }
        }

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

    private void DescribeEnumParameters(IDictionary<OperationType, OpenApiOperation> operations, OpenApiDocument swaggerDoc)
    {
        if (operations != null)
        {
            foreach (var oper in operations)
            {
                foreach (var param in oper.Value.Parameters)
                {
                    var paramEnum = swaggerDoc.Components.Schemas.FirstOrDefault(x => x.Key == param.Name);
                    if (paramEnum.Value != null)
                    {
                        param.Description += DescribeEnum(paramEnum.Value.Enum, paramEnum.Key);
                    }
                }
            }
        }
    }

    private Type GetEnumTypeByName(string enumTypeName)
    {
        return AppDomain.CurrentDomain
            .GetAssemblies()
            .SelectMany(x => x.GetTypes())
            .FirstOrDefault(x => x.Name == enumTypeName);
    }

    private string DescribeEnum(IList<IOpenApiAny> enums, string proprtyTypeName)
    {
        List<string> enumDescriptions = new List<string>();
        var enumType = GetEnumTypeByName(proprtyTypeName);
        if (enumType == null)
            return null;

        foreach (OpenApiInteger enumOption in enums)
        {
            int enumInt = enumOption.Value;

            enumDescriptions.Add(string.Format("{0} = {1}", enumInt, Enum.GetName(enumType, enumInt)));
        }

        return string.Join(", ", enumDescriptions.ToArray());
    }
}
Hosam Rehani
fonte
1
Isso só funciona quando o tipo de parâmetro é exatamente enum ... enum não anulável, coleção de enums etc. Verifique minha resposta para esses casos.
Matyas de
4

Acabei de fazer isso e funciona bem!

Startup.cs

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

Model.cs

public enum ColumnType {
  DATE = 0
}

swagger.json

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

Espero que isso ajude você como me ajudou!

Rodrigo Béco
fonte
2
DescribeAllEnumsAsStringsestá obsoleto
Node.JS de
4

em .net core 3.1 e swagger 5.0.0:

using System.Linq;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace WebFramework.Swagger
{
    public class EnumSchemaFilter : ISchemaFilter
    {
        public void Apply(OpenApiSchema schema, SchemaFilterContext context)
        {
            if (context.Type.IsEnum)
            {
                var enumValues = schema.Enum.ToArray();
                var i = 0;
                schema.Enum.Clear();
                foreach (var n in Enum.GetNames(context.Type).ToList())
                {
                    schema.Enum.Add(new OpenApiString(n + $" = {((OpenApiPrimitive<int>)enumValues[i]).Value}"));
                    i++;
                }
            }
        }
    }

}

e em Startup.cs:

services.AddSwaggerGen(options =>
            {
                #region  EnumDesc
                options.SchemaFilter<EnumSchemaFilter>();
                #endregion
            });

Resultado

ehsan rezaee
fonte
4
O lado negativo disso é que, ao executar uma solicitação, em vez de passar apenas a representação int (como 2 por exemplo) de um valor enum, a API obterá a descrição completa como um valor (como LogicError = 3), que falhará como um solicitação incorreta, pois não é um valor válido para o enum.
Matyas de
3

Minha variante para enum stings com valores:

insira a descrição da imagem aqui

Configure os serviços:

services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "web server api", Version = "v1" });
                c.SchemaFilter<EnumSchemaFilter>();
            });

Filtro:

public class EnumSchemaFilter : ISchemaFilter
    {
        public void Apply(OpenApiSchema model, SchemaFilterContext context)
        {
            if (context.Type.IsEnum)
            {
                model.Enum.Clear();
                Enum.GetNames(context.Type)
                    .ToList()
                    .ForEach(name => model.Enum.Add(new OpenApiString($"{Convert.ToInt64(Enum.Parse(context.Type, name))} - {name}")));
            }
        }
    }
Andrew Zaitsev
fonte
2

escrever código dentro de Startup.cs

services.AddSwaggerGen(c => {
      c.DescribeAllEnumsAsStrings();
    });
ANJYR - KODEXPRESSION
fonte
2
Esta opção está obsoleta no Swashbuckle. É recomendável usar a opção ASP.NET Core e, em seguida, Swashbuckle pode refletir isso.
Bashir Momen
2

Eu encontrei uma boa solução alternativa aqui:

@PauloVetor - resolveu usando ShemaFilter assim:

public class EnumSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema model, SchemaFilterContext context)
    {
        if (context.Type.IsEnum)
        {
            model.Enum.Clear();
            Enum.GetNames(context.Type)
                .ToList()
                .ForEach(n => model.Enum.Add(new OpenApiString(n)));
            }
        }
    }
}

E em Startup.cs:

services.AddSwaggerGen(options =>
{
    options.SchemaFilter<EnumSchemaFilter>();
}
hélice nebulosa
fonte
Você também deve certificar-se de atualizar o model.Formatpara "string"como geralmente será "int32".
lsuarez
1

.Net Core 3.0

   using Newtonsoft.Json.Converters;

 services
    .AddMvc(options =>
    {
     options.EnableEndpointRouting = false;
     })
    .AddNewtonsoftJson(options => options.SerializerSettings.Converters.Add(new StringEnumConverter()))
anil yıldırım
fonte
1
Ele está usando Newtonsoft em vez da nova serialização JSON do asp.net core.
Bashir Momen
1

Modifiquei a resposta de Hosam Rehani para trabalhar com enums anuláveis ​​e com coleção de enums também. A resposta anterior também funciona apenas se uma propriedade for nomeada exatamente como seu tipo. Todos esses problemas são tratados no código a seguir.

Funciona com .net core 3.xe swagger 5.x.

poderia ser mais eficiente não pesquisando o tipo de enum duas vezes em alguns casos.

class SwaggerAddEnumDescriptions : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        // add enum descriptions to result models
        foreach (var property in swaggerDoc.Components.Schemas.Where(x => x.Value?.Enum?.Count > 0))
        {
            IList<IOpenApiAny> propertyEnums = property.Value.Enum;
            if (propertyEnums != null && propertyEnums.Count > 0)
            {
                property.Value.Description += DescribeEnum(propertyEnums, property.Key);
            }
        }

        // add enum descriptions to input parameters
        foreach (var pathItem in swaggerDoc.Paths)
        {
            DescribeEnumParameters(pathItem.Value.Operations, swaggerDoc, context.ApiDescriptions, pathItem.Key);
        }
    }

    private void DescribeEnumParameters(IDictionary<OperationType, OpenApiOperation> operations, OpenApiDocument swaggerDoc, IEnumerable<ApiDescription> apiDescriptions, string path)
    {
        path = path.Trim('/');
        if (operations != null)
        {
            var pathDescriptions = apiDescriptions.Where(a => a.RelativePath == path);
            foreach (var oper in operations)
            {
                var operationDescription = pathDescriptions.FirstOrDefault(a => a.HttpMethod.Equals(oper.Key.ToString(), StringComparison.InvariantCultureIgnoreCase));
                foreach (var param in oper.Value.Parameters)
                {
                    var parameterDescription = operationDescription.ParameterDescriptions.FirstOrDefault(a => a.Name == param.Name);
                    if (parameterDescription != null && TryGetEnumType(parameterDescription.Type, out Type enumType))
                    {
                        var paramEnum = swaggerDoc.Components.Schemas.FirstOrDefault(x => x.Key == enumType.Name);
                        if (paramEnum.Value != null)
                        {
                            param.Description += DescribeEnum(paramEnum.Value.Enum, paramEnum.Key);
                        }
                    }
                }
            }
        }
    }

    bool TryGetEnumType(Type type, out Type enumType)
    {
        if (type.IsEnum)
        {
            enumType = type;
            return true;
        }
        else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
        {
            var underlyingType = Nullable.GetUnderlyingType(type);
            if (underlyingType != null && underlyingType.IsEnum == true)
            {
                enumType = underlyingType;
                return true;
            }
        }
        else
        {
            Type underlyingType = GetTypeIEnumerableType(type);
            if (underlyingType != null && underlyingType.IsEnum)
            {
                enumType = underlyingType;
                return true;
            }
            else
            {
                var interfaces = type.GetInterfaces();
                foreach (var interfaceType in interfaces)
                {
                    underlyingType = GetTypeIEnumerableType(interfaceType);
                    if (underlyingType != null && underlyingType.IsEnum)
                    {
                        enumType = underlyingType;
                        return true;
                    }
                }
            }
        }

        enumType = null;
        return false;
    }

    Type GetTypeIEnumerableType(Type type)
    {
        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
        {
            var underlyingType = type.GetGenericArguments()[0];
            if (underlyingType.IsEnum)
            {
                return underlyingType;
            }
        }

        return null;
    }

    private Type GetEnumTypeByName(string enumTypeName)
    {
        return AppDomain.CurrentDomain
            .GetAssemblies()
            .SelectMany(x => x.GetTypes())
            .FirstOrDefault(x => x.Name == enumTypeName);
    }

    private string DescribeEnum(IList<IOpenApiAny> enums, string proprtyTypeName)
    {
        List<string> enumDescriptions = new List<string>();
        var enumType = GetEnumTypeByName(proprtyTypeName);
        if (enumType == null)
            return null;

        foreach (OpenApiInteger enumOption in enums)
        {
            int enumInt = enumOption.Value;

            enumDescriptions.Add(string.Format("{0} = {1}", enumInt, Enum.GetName(enumType, enumInt)));
        }

        return string.Join(", ", enumDescriptions.ToArray());
    }
}

para usar o filtro, adicione c.DocumentFilter<SwaggerAddEnumDescriptions>();à configuração swagger em Startup.cs.

Matyas
fonte
0

SOLUÇÃO ASP NET

Em meus documentos de API, um enum ainda era mostrado como int, apesar de a propriedade estar marcada com StringEnumConverter. Não podíamos nos dar ao luxo de usar a configuração global para todos os enums mencionados acima. Adicionar esta linha no SwaggerConfig resolveu o problema:

c.MapType<ContactInfoType>(() => new Schema { type = "string", @enum = Enum.GetNames(typeof(ContactInfoType))});
kurdemol94
fonte
0

Encontrei uma série de deficiências nas outras respostas para o que estávamos procurando, então pensei em fornecer minha própria opinião sobre isso. Estamos usando ASP.NET Core 3.1 com System.Text.Json, mas nossa abordagem funciona independentemente do serializador JSON usado.

Nosso objetivo era aceitar valores de string enum com letras maiúsculas e minúsculas na API ASP.NET Core, bem como documentar os mesmos no Swagger. No momento, estamos usando [DataContract]e [EnumMember], portanto, a abordagem é pegar o valor de caixa baixa do camelo da propriedade de valor EnumMember e usá-lo em toda a linha.

Nosso exemplo de enum:

[DataContract]
public class enum Colors
{
  [EnumMember(Value="brightPink")]
  BrightPink,
  [EnumMember(Value="blue")]
  Blue
}

Usaremos os valores EnumMember no Swashbuckle usando um ISchemaFilter como a seguir:

public class DescribeEnumMemberValues : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        if (context.Type.IsEnum)
        {
            schema.Enum.Clear();

            //Retrieve each of the values decorated with an EnumMember attribute
            foreach (var member in context.Type.GetMembers())
            {
                var memberAttr = member.GetCustomAttributes(typeof(EnumMemberAttribute), false).FirstOrDefault();
                if (memberAttr != null)
                {
                    var attr = (EnumMemberAttribute) memberAttr;
                    schema.Enum.Add(new OpenApiString(attr.Value));
                }
            }
        }
    }
}

Nós estamos usando um pacote NuGet de terceiros (GitHub repo ) para garantir que este esquema de nomenclatura também é utilizada em ASP.NET Core. Configure-o em Startup.cs em ConfigureServices com:

services.AddControllers()
  .AddJsonOptions(opt => opt.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverterWithAttributeSupport()));

Finalmente, precisamos registrar nosso ISchemaFilter no Swashbuckle, então também adicionar o seguinte também em ConfigureServices ():

services.AddSwaggerGen(c => {
  c.SchemaFilter<DescribeEnumMemberValues>();
});
Xaniff
fonte
GetMembers()seria melhor GetMembers(BindingFlags.Static | BindingFlags.Public)limitar apenas às propriedades reais de enum declaradas, como "Azul". Eu também adaptei o caso "else" para retornar o Member.Name se não houver nenhum [EnumMember]atributo.
user2864740
0

Isso não é possível com o OpenAPI padrão. Enums são descritos apenas com seus valores de string.

Felizmente, você pode fazer isso com algumas extensões não padronizadas que são utilizadas por seu gerador de cliente.

Suporta NSwag x-enumNames

Suporta AutoRest x-ms-enum.

Suporta gerador Openapi x-enum-varnames

Outros geradores podem suportar uma dessas extensões ou ter as suas próprias.

Para gerar x-enumNamespara NSwag, crie o seguinte filtro de esquema:

public class EnumSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        if (context.Type.IsEnum)
        {
            var array = new OpenApiArray();
            array.AddRange(Enum.GetNames(context.Type).Select(n => new OpenApiString(n)));
            // NSwag
            schema.Extensions.Add("x-enumNames", array);
            // Openapi-generator
            schema.Extensions.Add("x-enum-varnames", array);
        }
    }
}

E registre-o como:

services.AddSwaggerGen(options =>
{
    options.SchemaFilter<EnumSchemaFilter>();
});
Norekhov
fonte