Swagger UI Web Api belgeleri Numaralandırmalar dizeler olarak sunulsun mu?


110

Tüm numaralandırmaları int değeri yerine swagger'da dize değeri olarak görüntülemenin bir yolu var mı?

Her seferinde numaralandırmaya bakmak zorunda kalmadan POST eylemleri gönderebilmek ve numaralandırmaları dize değerlerine göre koyabilmek istiyorum.

Denedim DescribeAllEnumsAsStringsama sunucu aradığımız şey olmayan enum değeri yerine dizeler alıyor.

Bunu kimse çözdü mü?

Düzenle:

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
Şemanın değeri bir dizge olarak tanımlamasını, ancak ardından sunucuya bir tamsayı göndermesini mi istiyorsunuz? JSON.net her iki değeri de iyi işleyecektir, bu nedenle yalnızca tamsayı sürümü kesin bir gereklilik midir? Swagger'ın hem dize hem de tamsayı değerine sahip bir enum türünü desteklediğini sanmıyorum.
Hux

1
Beklediğiniz davranış net değil, Swagger UI'nin ne göstermesini istediğinizi ve Web API'nize neyi POST / PUT yapmak istediğinizi örneklerle daha iyi açıklayabilir misiniz?
Federico Dipuma

Dahası, url'de numaralandıran GET yöntemlerim varsa, şemanın onu önerilen değerler açılır listesinde dizeler olarak tanımlamasını istiyorum

Tam sayı doğrulaması neden başarısız oluyor? Tür, modeldeki bir enum olmalıdır ve json ortam biçimlendiricisi bir dizeyi veya int'i doğru şekilde işleyecektir. Soruyu bir örnekle güncellerseniz, doğrulamanın neden başarısız olduğunu anlamamıza yardımcı olur.
Hux

4
Bu bir bayrak sıralamasıysa, olası her bayrak kombinasyonu için tanımlanmış enum değerleriniz olmadığı sürece sayısal olmalıdır. Swagger'ın her bir numaralandırma için HİÇBİR ad ve değeri göstermemesi ve bunun yerine tek başına sayıyı (işe yaramaz) veya tek başına isimleri (yine, sayı olarak belirtilmesi gereken bayraklar için kullanışsız) göstermesi somuttur.
Triynko

Yanıtlar:


189

Gönderen docs :

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

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

Ayrıca, bu davranışı yalnızca belirli bir tür ve özellikte istiyorsanız, StringEnumConverter'ı kullanın:

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

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

5
bu benim için çalışmıyor. [EnumDataType (typeof (Priority))] [JsonConverter (typeof (StringEnumConverter))]
Lineker

@NH. evet, newtonsoft.json kullandım
Lineker

@Lineker, bu kılavuzu izleyerek hatanızı yeni bir soru olarak gönderin: stackoverflow.com/help/mcve
NH.

Teşekkürler! Ben sadece çok #thiswilldothetrick kaynağındaki Yorum bırakmak olabileceğini düşünüyorum
Simon_Weaver

5
DescribeAllEnumsAsStringsnesne özellikleri ve hatta denetleyici eylemlerindeki sorgu parametreleri için çalıştı. Ancak, kullanmak EnumDataTypeAttributeve JsonConverter(typeof(StringEnumConverter))benim için işe yaramadı.
bugged87

97

Microsoft JSON kitaplığı (System.Text.Json) ile ASP.NET Core 3 için

Startup.cs / ConfigureServices () içinde:

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

Json.NET (Newtonsoft.Json) kitaplığına sahip ASP.NET Core 3 için

Yükle Swashbuckle.AspNetCore.NewtonsoftPaketi .

Startup.cs / ConfigureServices () içinde:

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 için

Startup.cs / ConfigureServices () içinde:

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 ())), sadece Sawshbuckle için değil, tüm yöntemleriniz için json'u değiştirdiğinizdir.
Guillaume

Azure İşlevleri v2 ve / veya v3 için çözümü olan var mı?
Dan Friedman

@DanFriedman Swashbuckle'ın Azure Functions ile hiç çalışmadığını düşünürsek şansınız kalmaz.
Ian Kemp

@IanKemp Pakette üçüncü taraf desteği var AzureExtensions.Swashbuckleama @DanFriedman gibi beklendiği gibi enum-to-string çalışmasını
sağlayamıyorum

40

Sanırım benzer bir sorunum var. İnt -> string eşleme ile birlikte numaralandırmak için swagger arıyorum. API, int kabul etmelidir. Swagger-ui daha az önemli, gerçekten istediğim şey, diğer tarafta "gerçek" bir numaralandırma ile kod üretmektir (bu durumda retrofit kullanan android uygulamaları).

Yani araştırmamdan bu sonuçta Swagger'ın kullandığı OpenAPI spesifikasyonunun bir sınırı gibi görünüyor. Numaralandırmalar için ad ve numara belirtmek mümkün değildir.

Takip ettiğim en iyi sorun https://github.com/OAI/OpenAPI-Specification/issues/681 "belki yakında" gibi görünen ancak ardından Swagger'ın güncellenmesi gerekir ve benim durumumda Swashbuckle iyi.

Şimdilik çözümüm, numaralandırmaları arayan ve ilgili açıklamayı numaralamanın içeriğiyle dolduran bir belge filtresi uygulamak oldu.

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

}

Bu, swagger-ui'nizde aşağıdakine benzer bir şeyle sonuçlanır, böylece en azından "ne yaptığınızı görebilirsiniz": görüntü açıklamasını buraya girin


1
+1 Numaralandırmalara açıklamalar eklemek istiyordum (sadece 'numaralandırmayı tanımlamak' için), bunu hiç düşünmemiştim. Zaten yerinde çeşitli filtrelerim var, ancak daha 'organik' bir şeyler arıyordum, ancak destek yok. Öyleyse, tüm yolu filtreler :)
NSGaga-çoğunlukla etkin değil

Teşekkürler! Bunu projemde kullandım, ancak .NET Core ile çalışacak şekilde değiştirdim. Uygulamamı cevap olarak ekledim.
Gabriel Luci

27

ASP.NET Core 3.1

Newtonsoft JSON kullanarak dizeler olarak numaralandırmak için AddSwaggerGenNewtonsoftSupport(), aşağıdaki gibi ekleyerek Newtonsoft desteğini açıkça eklemelisiniz :

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


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

Bu, yeni bir paket aracılığıyla edinilebilir Swashbuckle.AspNetCore.Newtonsoft. Enum dönüştürücü desteği dışında bu paket olmadan her şey iyi çalışıyor gibi görünüyor.


1
Bu kuralı genel olarak kurmanıza yardımcı olur, ancak bunu yalnızca belirli numaralandırma türlerine uygulamanız gerekiyorsa, bu sorunu dikkatlice okumanız gerekir . TL; DR: Yeni StringEnumConverter () 'ı yalnızca özelliğe uygulamak mümkün değildir, ancak bunu tüm enum türüne uygulayabilirsiniz.
A. Tretiakov

1
Sanırım gotchas'tan bahsediyorsak, tamamen özel bir dönüştürücü kullanmak da mümkün değil. Swagger, enum değerlerini özel dönüştürücü aracılığıyla çalıştırmaz; basitçe StringEnumConverterözel bir durum olarak kabul edilir.
Roma Starkov

22

Rory_za'nın yanıtını bir .NET Core uygulamasında kullanmak istedim, ancak çalışmasını sağlamak için biraz değiştirmem gerekti. İşte .NET Core için bulduğum uygulama.

Ayrıca onu değiştirdim, böylece altta yatan türü varsaymasın ve intdaha kolay okumak için değerler arasında yeni satırlar kullanın.

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

Ardından bunu ConfigureServicesStartup.cs içindeki yönteminize ekleyin :

c.DocumentFilter<EnumDocumentFilter>();

Aşağıda görünen Enum: Array [6] kaldırılabilir mi?
Softlion

4
Harika bir çözüm, ancak projemdeki uzantılar DescribeEnumParametersboştu. Yayınlayabileceğim zorunda paramiçin NonBodyParameterve orada enum kontrol edin:if (param is NonBodyParameter nbParam && nbParam.Enum?.Any() == true) { param.Description += DescribeEnum(nbParam.Enum); }
Rabban

Projemde Uzantılar da boş, @Rabban çözümünü kullandım.
Carlos Beppler

1
@Rabban Kodumu bunu içerecek şekilde güncelledim. Doğru yere koyduğumu doğrulayabilir misin? Bu sorunu yaşamadım. Belki daha yeni bir sürüm bazı şeyleri değiştirdi.
Gabriel Luci

@GabrielLuci Onaylandı ve onaylandı;)
Rabban

12

Asp.net core 3 ile

using System.Text.Json.Serialization;

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

Ancak görünen o ki, Swashbuckle Sürüm 5.0.0-rc4 bunu desteklemeye hazır değil. Bu yüzden Swashbuckle yapılandırma dosyasında Newtonsoft kitaplığı gibi destekleyip yansıtana kadar bir seçenek (kullanımdan kaldırılmış) kullanmamız gerekiyor.

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

Bu yanıtla diğer yanıtlar arasındaki fark, Newtonsoft yerine yalnızca Microsoft JSON kitaplığını kullanmaktır.


Hey @ Bashir, bu desteğin eksikliğini takip etmek için bir swachbuckle sorunu var mı?
Bernard Vander Beken

Merhaba @ bernard-vander-beken, bunu rapor etmedim ama olduğunu varsayıyorum. Onu bulabilirsek ve daha sonraki güncellemeler için bu yazıya ekleyebilirsek iyi olur.
Bashir Momen


11

ilgilenen varsa, çalışmak için kodu değiştirdim

.NET CORE 3 ve 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
Bu yalnızca parametre türü tam olarak enum olduğunda çalışır ... boş değer atanabilir enum değil, numaralandırma koleksiyonu vb. Bu durumlar için cevabımı kontrol edin.
Matyas

Bu kodu çalıştırdığımda, enumOption'ın DescribeEnum
Kirsten

11

.NET CORE 3.1 ve SWAGGER 5

dizeleri seçmeli olarak geçiren numaralandırmak için basit bir çözüme ihtiyacınız varsa :

using System.Text.Json.Serialization;


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

Not, System.Text.Json.Serializationad alanını kullanıyoruz Newtonsoft.Json,!


Bu, uygun değerleri göstererek çalışır ve aynı zamanda değerleri numaralandırmaya geri dönüştürürken de çalışır. NuGet paketini eklemeniz gerektiğini unutmayın System.Text.Json.
MovGP0

Ben de bunu arıyordum! Sadece tek bir enum için string kullanmam gerektiğinden ve DescribeAllEnumsAsStringstüm numaralandırmaları dizeye dönüştüreceğim.
Nilay

Bu basit çözüm için teşekkürler. .NET Core 3.1 ve Swagger 5.5 kullanıyorum. DescribeAllEnumsAsStrings kullanmasına gerek yoktu. Enum'da [JsonConverter (typeof (JsonStringEnumConverter))] 'ı ayarlayın. ÖR: System.Text.Json.Serialization; [JsonConverter (typeof (JsonStringEnumConverter))] genel enum Kategori {Otomobiller, Elektronikler, Mobilya, Ev, Evcil Hayvanlar, Çeşitli}
Mahesh

4

Bunu yeni yaptım ve iyi çalışıyor!

Startup.cs

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

Model.cs

public enum ColumnType {
  DATE = 0
}

swagger.json

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

Umarım bu bana nasıl yardım ettiğine yardımcı olur!


2
DescribeAllEnumsAsStringskullanımdan kaldırıldı
Node.JS

4

.net core 3.1 ve swagger 5.0.0'da:

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

}

ve Startup.cs içinde:

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

Sonuç


4
Bunun olumsuz yanı, bir isteği yürütürken, bir enum değerinin yalnızca int gösterimini (örneğin 2 gibi) iletmek yerine, API'nin tam açıklamayı bir değer olarak (LogicError = 3 gibi) alacağıdır ve bu, bir enum için geçerli bir değer olmadığından hatalı istek.
Matyas

3

Değerleri olan numaralandırma sokmaları için değişkenim:

görüntü açıklamasını buraya girin

Hizmetleri Yapılandırın:

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

Filtrele:

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 içine kod yazın

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

2
Bu seçenek Swashbuckle'da kullanımdan kaldırılmıştır. ASP.NET Core seçeneğinin kullanılması önerilir ve ardından Swashbuckle bunu yansıtabilir.
Bashir Momen

2

Burada güzel bir çözüm buldum:

@PauloVetor - bunu ShemaFilter kullanarak şu şekilde çözdü:

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

Ve Startup.cs içinde:

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

Ayrıca güncellemek emin olmalıdır model.Formatiçin "string"genellikle olacağı gibi "int32".
lsuarez

2

Hosam Rehani'nin cevabını null yapılabilir numaralandırmalarla ve ayrıca numaralandırma koleksiyonuyla çalışmak üzere değiştirdim. Önceki cevap, yalnızca bir özellik tam olarak türüne benzer şekilde adlandırılırsa işe yarar. Tüm bu sorunlar aşağıdaki kodda ele alınmaktadır.

.Net core 3.x ve swagger 5.x ile çalışır.

bazı durumlarda numaralandırma türünü iki kez aramamak daha verimli olabilir.

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

filtreyi kullanmak için c.DocumentFilter<SwaggerAddEnumDescriptions>();, içinde swagger yapılandırmasına ekleyin 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
Yeni asp.net core JSON serileştirmesi yerine Newtonsoft kullanıyor.
Bashir Momen

1

Bu standart OpenAPI ile mümkün değildir. Numaralandırmalar yalnızca dize değerleriyle açıklanır.

Neyse ki, bunu istemci oluşturucunuz tarafından kullanılan bazı standart dışı uzantılarla yapabilirsiniz.

NSwag destekler x-enumNames

AutoRest destekler x-ms-enum.

Openapi-jeneratör destekleri x-enum-varnames

Diğer üreticiler bu uzantılardan birini destekleyebilir veya kendilerine ait olabilir.

Oluşturmak için x-enumNamesNSwag için aşağıdaki şema filtre oluşturun:

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

Ve şu şekilde kaydedin:

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

0

ASP NET ÇÖZÜM

API belgelerimde, özellik ile işaretlenmiş olmasına rağmen bir enum hala int olarak gösteriliyordu StringEnumConverter. Yukarıda bahsedilen tüm numaralandırmalar için genel ayarı kullanmayı göze alamazdık. SwaggerConfig'e bu satırı eklemek sorunu çözdü:

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

0

Aradığımız şey için diğer cevaplarda bulduğum bir takım eksiklikler vardı, bu yüzden bu konudaki görüşümü kendim sağlayacağımı düşündüm. System.Text.Json ile ASP.NET Core 3.1 kullanıyoruz, ancak yaklaşımımız kullanılan JSON serileştiriciden bağımsız olarak çalışıyor.

Amacımız, hem ASP.NET Core API'de daha düşük deve harfli numaralandırma dizesi değerlerini kabul etmek hem de Swagger'da aynı şeyi belgelemekti. Şu anda yararlanarak konum [DataContract]ve[EnumMember] yaklaşım karşısında kurulu olduğu EnumMember değeri mülkiyet ve kullanımdan alt-deve kasalı değeri almaktır böylece.

Örnek numaramız:

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

Swashbuckle'da EnumMember değerlerini, aşağıdaki gibi bir ISchemaFilter kullanarak kullanacağız:

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

Bu adlandırma şemasının ASP.NET Core'da da kullanıldığından emin olmak için üçüncü taraf bir NuGet paketi (GitHub deposu ) kullanıyoruz. ConfigureServices içindeki Startup.cs içinde şu şekilde yapılandırın:

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

Son olarak, ISchemaFilter'ımızı Swashbuckle'a kaydetmemiz gerekiyor, bu nedenle ConfigureServices () 'e aşağıdakileri de eklememiz gerekiyor:

services.AddSwaggerGen(c => {
  c.SchemaFilter<DescribeEnumMemberValues>();
});

GetMembers()GetMembers(BindingFlags.Static | BindingFlags.Public)"Mavi" gibi yalnızca gerçek bildirilen enum özelliklerini sınırlamak daha iyi olacaktır . Ayrıca "else" durumunu, eğer [EnumMember]öznitelik yoksa Member.Name'i iade edecek şekilde uyarladım .
user2864740

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.