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

110

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

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

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

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

Редактировать:

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
}

источник
1
Вы хотите, чтобы схема описывала значение как строку, но затем отправляла целое число на сервер? JSON.net отлично справится с обоими значениями, поэтому является ли целочисленная версия определенным требованием? Я не думаю, что Swagger поддерживает перечисляемый тип со строковым и целочисленным значением.
Hux
1
Ваше ожидаемое поведение неясно, не могли бы вы лучше объяснить, что вы хотите, чтобы пользовательский интерфейс Swagger отображал и что вы хотите POST / PUT в свой веб-API с примерами?
Федерико Дипума
Более того, если у меня есть методы GET, которые принимают перечисление в URL-адресе, я хочу, чтобы схема описывала его как строки в раскрывающемся списке предлагаемых значений
Почему не удается проверить целочисленные значения? Тип должен быть перечислением в модели, и средство форматирования мультимедиа json будет правильно обрабатывать либо строку, либо int. Если вы дополните вопрос примером, это поможет нам понять, почему проверка не выполняется.
Hux
4
Если это перечисление флагов, оно должно быть числовым, если только у вас не определены значения перечисления для каждой возможной комбинации флагов. Это безумие, что swagger не отображает ОБА имени и значения для каждого перечисления, а вместо этого отображает только число (бесполезно) или только имена (опять же, бесполезно для флагов, которые должны быть указаны как числа).
Трийнко

Ответы:

189

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

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;}
}
Ксаверо
источник
5
это не работа для меня [EnumDataType (TypeOf (Priority))] [JsonConverter (TypeOf (StringEnumConverter))].
Линекер
@NH. да, я использовал newtonsoft.json
Линекер
@Lineker, опубликуйте свою ошибку как новый вопрос, следуя этому руководству: stackoverflow.com/help/mcve
NH.
Спасибо! Думаю, я мог бы просто оставить ваш комментарий в источнике #thiswilldothetrick
Simon_Weaver
5
DescribeAllEnumsAsStringsработал со свойствами объекта и даже с параметрами запроса для действий контроллера. Однако использование EnumDataTypeAttributeи JsonConverter(typeof(StringEnumConverter))у меня не сработало.
bugged87
97

Для ASP.NET Core 3 с библиотекой Microsoft JSON (System.Text.Json)

В Startup.cs / ConfigureServices ():

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

Для ASP.NET Core 3 с библиотекой Json.NET (Newtonsoft.Json)

Установите Swashbuckle.AspNetCore.Newtonsoftпакет.

В Startup.cs / ConfigureServices ():

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

Для ASP.NET Core 2

В Startup.cs / ConfigureServices ():

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

Pre-ASP.NET Core

httpConfiguration
    .EnableSwagger(c => 
        {
            c.DescribeAllEnumsAsStrings();
        });
Ли Ричардсон
источник
4
Проблема использования options.SerializerSettings.Converters.Add (new StringEnumConverter ())) заключается в том, что вы меняете json для всех своих методов, а не только для Sawshbuckle.
Гийом
Есть ли у кого-нибудь решение для функций Azure v2 и / или v3?
Дэн Фридман
@DanFriedman Учитывая, что Swashbuckle вообще не работает с функциями Azure, вам не повезло.
Ян Кемп,
@IanKemp В пакете есть сторонняя поддержка AzureExtensions.Swashbuckle, но, как и @DanFriedman, я не могу заставить enum-to-string работать
должным образом
40

Думаю, у меня похожая проблема. Я ищу чванство для генерации перечислений вместе с сопоставлением строк int ->. 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 = 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());
    }

}

В результате в вашем swagger-ui появляется что-то вроде следующего, чтобы вы хотя бы могли «видеть, что делаете»: введите описание изображения здесь

Рори
источник
1
+1 Я хотел добавить описания к перечислениям (просто чтобы «описать перечисления»), никогда не думал об этом. У меня уже есть разные фильтры, но я искал что-то более «органичное», но поддержки нет. Ну тогда
фильтруйте полностью
Спасибо! Я использовал это в своем проекте, но модифицировал для работы с .NET Core. Я добавил свою реализацию в качестве ответа.
Габриэль Люси
27

ASP.NET Core 3.1

Чтобы сгенерировать перечисления в виде строк с использованием Newtonsoft JSON, вы должны явно добавить поддержку Newtonsoft, добавив AddSwaggerGenNewtonsoftSupport()следующее:

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


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

Это доступно в новом пакете Swashbuckle.AspNetCore.Newtonsoft. Похоже, что все остальное отлично работает без этого пакета, кроме поддержки enum converter.

Роман Старков
источник
1
Это помогает настроить это соглашение глобально, но если вам нужно применить его только к определенным типам перечислений, вам нужно будет внимательно прочитать эту проблему . TL; DR: Невозможно применить new StringEnumConverter () только к свойству, но вы можете применить его ко всему типу перечисления.
А. Третьяков
1
Я полагаю, что если мы говорим о проблемах, также невозможно использовать полностью настраиваемый конвертер. Swagger не запускает значения перечисления через специальный конвертер; это просто StringEnumConverterрассматривается как частный случай.
Роман Старков
22

Я хотел использовать ответ 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>();
Габриэль Люси
источник
Можно ли удалить Enum: Array [6], которое отображается ниже?
Softlion
4
Отличное решение, но DescribeEnumParametersв моем проекте расширения были пустыми. Я должен был забрасывать paramк NonBodyParameterи проверить перечисление там:if (param is NonBodyParameter nbParam && nbParam.Enum?.Any() == true) { param.Description += DescribeEnum(nbParam.Enum); }
Раббан
В моем проекте Extensions тоже пустые, использовал решение @Rabban.
Карлос Бепплер
1
@Rabban Я обновил свой код, включив это. Вы можете просто проверить, что я поместил его в нужное место? У меня не было этой проблемы. Возможно, более новая версия изменила ситуацию.
Габриэль Люси
@GabrielLuci Подтвержденные и утвержден;)
Раббан
12

С ядром 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 Version 5.0.0-rc4 не готов поддерживать это. Поэтому нам нужно использовать параметр (устаревший) в файле конфигурации Swashbuckle, пока он не будет поддерживать и отражать его как библиотеку Newtonsoft.

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

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

Башир Момен
источник
Привет, @Bashir, есть ли проблема с муфтой, чтобы отслеживать отсутствие этой поддержки?
Бернард Вандер Бекен
Привет @ bernard-vander-beken, я не сообщал об этом, но полагаю, что есть. Хорошо, если мы сможем найти его и добавить в этот пост для последующих обновлений.
Башир
2
Похоже, это здесь: github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1269
Jeremyh
11

если кому-то интересно, я изменил код для работы с

.NET CORE 3 и 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());
    }
}
Хосам Рехани
источник
1
Это работает только тогда, когда тип параметра точно enum ... не обнуляемое перечисление, коллекция перечислений и т. Д. Проверьте мой ответ для этих случаев.
Матиас
Когда я запускаю этот код, я обнаруживаю, что enumOption имеет тип OpenApiString в DescribeEnum
Kirsten Greed
10

.NET CORE 3.1 и SWAGGER 5

если вам нужно простое решение, чтобы выборочно передавать перечисления в виде строк:

using System.Text.Json.Serialization;


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

Обратите внимание, мы используем System.Text.Json.Serializationпространство имен, а не Newtonsoft.Json!

VeganHunter
источник
Этот работает, показывая правильные значения, а также работает при преобразовании значений обратно в перечисление. Обратите внимание, что вам нужно добавить пакет NuGet System.Text.Json.
MovGP0,
Вот что я искал! Поскольку мне нужно использовать строку только для одного перечисления, и я DescribeAllEnumsAsStringsконвертирую все перечисления в строку.
Нилай,
4

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

Startup.cs

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

Model.cs

public enum ColumnType {
  DATE = 0
}

swagger.json

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

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

Родриго Беко
источник
2
DescribeAllEnumsAsStringsустарела
Node.JS
4

в .net core 3.1 и 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++;
                }
            }
        }
    }

}

и в Startup.cs:

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

Результат

Ehsan Rezaee
источник
4
Обратной стороной этого является то, что при выполнении запроса вместо передачи только int-представления (например, 2) значения перечисления API получит полное описание в виде значения (например, LogicError = 3), что приведет к ошибке неверный запрос, поскольку это недопустимое значение для перечисления.
Матиас
3

Мой вариант для enum stings со значениями:

введите описание изображения здесь

Настроить службы:

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

Фильтр:

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}")));
            }
        }
    }
Андрей Зайцев
источник
2

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

services.AddSwaggerGen(c => {
      c.DescribeAllEnumsAsStrings();
    });
АНЖЫР - КОДЭКСПРЕССИЯ
источник
2
Эта опция устарела в Swashbuckle. Рекомендуется использовать параметр ASP.NET Core, и тогда Swashbuckle сможет это отразить.
Башир
2

Я нашел здесь хорошее решение:

@PauloVetor - решил с помощью ShemaFilter вот так:

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

И в Startup.cs:

services.AddSwaggerGen(options =>
{
    options.SchemaFilter<EnumSchemaFilter>();
}
спиральная туманность
источник
Вы также должны убедиться, что обновили model.Formatдо, "string"как обычно "int32".
Исуарес
2

Я изменил ответ Хосама Рехани для работы с перечислениями с нулевым значением, а также с коллекцией перечислений. Предыдущий ответ также работает только в том случае, если свойство названо точно так же, как его тип. Все эти проблемы решаются в приведенном ниже коде.

Он работает с .net core 3.x и swagger 5.x.

в некоторых случаях это могло бы быть более эффективно, если бы не искать тип перечисления дважды.

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());
    }
}

чтобы использовать фильтр добавьте c.DocumentFilter<SwaggerAddEnumDescriptions>();в конфигурацию swagger в Startup.cs.

Матиас
источник
1

.Net Core 3.0

   using Newtonsoft.Json.Converters;

 services
    .AddMvc(options =>
    {
     options.EnableEndpointRouting = false;
     })
    .AddNewtonsoftJson(options => options.SerializerSettings.Converters.Add(new StringEnumConverter()))
анил йылдырым
источник
1
Он использует Newtonsoft вместо новой сериализации JSON ядра asp.net.
Башир
1

Это невозможно со стандартным OpenAPI. Перечисления описываются только их строковыми значениями.

К счастью, вы можете сделать это с помощью некоторых нестандартных расширений, которые используются вашим генератором клиентов.

NSwag поддерживает x-enumNames

AutoRest поддерживает x-ms-enum .

Openapi-generator поддерживает x-enum-varnames

Другие генераторы могут поддерживать одно из этих расширений или иметь свои собственные.

Чтобы сгенерировать x-enumNamesдля NSwag, создайте следующий фильтр схемы:

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

И зарегистрируйте его как:

services.AddSwaggerGen(options =>
{
    options.SchemaFilter<EnumSchemaFilter>();
});
норехов
источник
0

РЕШЕНИЕ ASP NET

В моих документах api одно перечисление по-прежнему отображалось как int, несмотря на то, что свойство было отмечено значком StringEnumConverter. Мы не могли позволить себе использовать глобальные настройки для всех перечисленных выше перечислений. Добавление этой строки в SwaggerConfig решило проблему:

c.MapType<ContactInfoType>(() => new Schema { type = "string", @enum = Enum.GetNames(typeof(ContactInfoType))});
kurdemol94
источник
0

В других ответах на то, что мы искали, я обнаружил ряд недостатков, поэтому я подумал, что предоставлю свой собственный взгляд на это. Мы используем ASP.NET Core 3.1 с System.Text.Json, но наш подход работает независимо от используемого сериализатора JSON.

Наша цель состояла в том, чтобы принимать строковые значения перечисления в нижнем регистре как в API ASP.NET Core, так и задокументировать то же самое в Swagger. В настоящее время мы используем [DataContract]и[EnumMember] , поэтому подход состоит в том, чтобы взять значение в нижнем регистре из свойства EnumMember value и использовать его повсеместно.

Наш пример перечисления:

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

Мы будем использовать значения EnumMember в Swashbuckle, используя ISchemaFilter, как показано ниже:

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

Мы используем сторонний NuGet пакет (GitHub репо ) , чтобы гарантировать , что эта схема именования также используется в ASP.NET Core. Настройте его в Startup.cs в ConfigureServices с помощью:

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

Наконец, нам нужно зарегистрировать наш ISchemaFilter в Swashbuckle, поэтому также добавьте следующее в ConfigureServices ():

services.AddSwaggerGen(c => {
  c.SchemaFilter<DescribeEnumMemberValues>();
});
Ксанифф
источник
GetMembers()было бы лучше GetMembers(BindingFlags.Static | BindingFlags.Public)ограничиться только фактическими объявленными свойствами перечисления, такими как "Blue". Я также адаптировал случай «else», чтобы возвращать Member.Name, если [EnumMember]атрибута нет .
user2864740,