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


107

Чи є спосіб відобразити всі перерахунки як їхні рядкові значення в swagger замість їх int значення?

Я хочу мати змогу надсилати дії POST та встановлювати перерахунки відповідно до їх рядкового значення, не потребуючи щоразу дивитися на перерахунок.

Я спробував, DescribeAllEnumsAsStringsале сервер потім отримує рядки замість значення enum, яке не є тим, що ми шукаємо.

Хтось вирішив це?

Редагувати:

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 підтримує enum-тип із значенням string та integer.
Хукс

1
Ваша очікувана поведінка незрозуміла, чи можете ви краще пояснити, який саме інтерфейс Swagger відображатиметься, і що ви хочете POST / PUT для вашого веб-API з прикладами?
Федеріко Діпума

Більше того, якщо у мене є методи GET, які перераховують URL-адресу, я хочу, щоб схема описувала його як рядки у випадаючому списку запропонованих значень

Чому перевірка цілочисельних помилок не вдається? Тип повинен бути перерахунком у моделі, і формат медіаформатора json правильно обробляє або рядок, або int. Якщо ви оновите питання на прикладі, це допоможе нам зрозуміти, чому перевірка не працює.
Хукс

4
Якщо це прапор enum, він повинен бути числовим, якщо ви не визначаєте значення enum для кожної можливої ​​комбінації прапорів. Гайками є те, що шахрай не відображає імені та значення для кожного перерахунку, а натомість відображає лише одне число (непотрібне) або лише імена (знову ж таки, марне для прапорів, яке повинно бути вказане як цифри).
Трайнко

Відповіді:


188

З документів :

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 (Пріоритет))] [JsonConverter (typeof (StringEnumConverter))]
Lineker

@NH. так, я використав newtonsoft.json
Lineker

@Lineker, опублікуйте свою помилку як нове запитання, дотримуючись цього керівництва: stackoverflow.com/help/mcve
NH.

Дякую! Я думаю, що я можу просто залишити ваш коментар у джерелі #thiswilldothetrick
Simon_Weaver

5
DescribeAllEnumsAsStringsпрацював на властивості об'єкта і навіть параметри запиту на дії контролера. Однак користуватися EnumDataTypeAttributeі JsonConverter(typeof(StringEnumConverter))не вийшло у мене.
помилився87

90

Для 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 (новий StringEnumConverter ())) полягає в тому, що ви змінюєте json для всіх своїх методів, а не тільки для Sawshbuckle.
Гійом

Хтось має рішення для функцій Azure v2 та / або v3?
Ден Фрідман

@DanFriedman Вважаючи, що Swashbuckle взагалі не працює з функціями Azure, вам не пощастило.
Ян Кемп

@IanKemp Існує підтримка третьої сторони з AzureExtensions.Swashbuckleпакетом, але, як @DanFriedman, я не можу зробити так, щоб очікування працювало як очікується
wolfyuk

40

Тому я думаю, що у мене є подібна проблема. Я шукаю шахрая, щоб генерувати перерахунки разом із int -> string mapping. API повинен приймати int. Найбільш важливим є те, що я дуже хочу - це генерування коду з "реальним" перерахунком з іншого боку (андроїд-додатки, що використовують модернізацію в цьому випадку).

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

Найкраща проблема, яку я виявив, - це https://github.com/OAI/OpenAPI-Specification/isissue/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());
    }

}

Це призводить до чогось подібного у вашому повороті, щоб принаймні ви могли "бачити, що ви робите": введіть тут опис зображення


1
+1 Я шукав, щоб додати описи до переліків (просто для того, щоб "описати перелік"), ніколи про це не думав. У мене вже є фільтри мізків, але я шукав щось більш "органічне", але підтримки немає. Ну тоді фільтруємо до кінця :)
NSGaga - переважно-неактивний

Дякую! Я використовував це у своєму проекті, але змінив його для роботи з .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. Схоже, що все інше працює без цього пакета, окрім підтримки перетворювача.


1
Це допомагає налаштувати цю конвенцію в усьому світі, але якщо вам потрібно застосувати це лише до певних типів переліків, вам потрібно буде уважно прочитати це питання . TL; ДР: Неможливо застосувати новий StringEnumConverter () лише до властивості, але ви можете застосувати його до всього типу перерахунків.
А. Третьяков

1
Я припускаю, що якщо ми говоримо про gotchas, також не можливо використовувати повністю користувальницький конвертер. Swagger не запускає значення enum через спеціальний перетворювач; його просто визнають 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); }
Раббан

У моєму проекті Розширення також порожні, використовували рішення @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 Версія 5.0.0-rc4 не готова це підтримати. Тому нам потрібно використовувати параметр (застарілий) у конфігураційному файлі Swashbuckle, поки він не підтримує та не відображає його як бібліотеку Newtonsoft.

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

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


Привіт, @Bashir, чи є проблема з перемичкою, щоб відслідковувати відсутність такої підтримки?
Бернард Вандер Бекен

Привіт @ bernard-vander-beken, я не повідомив про це, але припускаю, що є. Добре, якщо ми зможемо знайти його та додати до цієї публікації для подальшого оновлення.
Башир


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!


Цей працює, показуючи належні значення, а також працює при перетворенні значень на перерахунок. Зауважте, що вам потрібно додати пакет NuGet System.Text.Json.
MovGP0

Ось що я шукав! Оскільки я повинен використовувати рядок лише для одного перерахунку, і DescribeAllEnumsAsStringsперетворять усі перерахунки у рядок.
Нілай

9

якщо хтось зацікавлений, я змінив код для роботи

.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
Це працює лише тоді, коли тип параметра є точно перерахуванням ... не нульовим перерахунком, колекцією перерахунків тощо. Перевірте свою відповідь на ці випадки.
Матяш

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

Результат


4
Недоліком цього є те, що при виконанні запиту, замість передачі лише int-репрезентації (як, наприклад, 2) значення enum, API отримає повний опис у вигляді значення (як LogicError = 3), яке не вдасться поганий запит, оскільки це недійсне значення для перерахунку.
Матяш

3

Мій варіант для перекусів із значеннями:

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

Налаштування послуг:

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".
lsuarez

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 core Asp.net.
Башир

1

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

Він працює з .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>();для конфігурації шахрая в Startup.cs.


0

ASP NET РІШЕННЯ

У моїх документах api один перерахунок все ще відображався як int, незважаючи на те, що властивість позначено символом StringEnumConverter. Ми не могли дозволити собі використовувати глобальний параметр для всіх перелічених вище переліків. Додавання цього рядка в SwaggerConfig вирішило проблему:

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

0

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

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

Наш зразок перерахунку:

[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 repo ) для того, щоб ця схема імен також використовувалася в 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)обмежитися лише фактичними оголошеними властивостями enum, такими як "Blue". Я також адаптував випадок "else", щоб повернути Member.Name, якщо немає [EnumMember]атрибута.
користувач2864740

0

Це неможливо при стандартному OpenAPI. Переліки описуються лише їх рядковими значеннями.

На щастя, ви можете зробити це за допомогою нестандартних розширень, які використовує ваш клієнт-генератор.

NSwag підтримує x-enumNames

Підтримка AutoRest x-ms-enum.

Опори-генератори підтримують 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>();
});

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.