Dokumentasi Api Web UI Swagger Menampilkan enum sebagai string?

107

Apakah ada cara untuk menampilkan semua enum sebagai nilai stringnya dalam swagger alih-alih nilai intnya?

Saya ingin dapat mengirimkan tindakan POST dan memasukkan enum sesuai dengan nilai stringnya tanpa harus melihat enum setiap saat.

Saya mencoba DescribeAllEnumsAsStringstetapi server kemudian menerima string alih-alih nilai enum yang bukan yang kami cari.

Apakah ada yang memecahkan ini?

Edit:

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

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


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

        ..
    }

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

    }
}


public enum Priority
{
    Low, 
    Medium,
    High
}

sumber
1
Apakah Anda ingin skema mendeskripsikan nilai sebagai string tetapi kemudian memposting integer ke server? JSON.net akan menangani kedua nilai dengan baik, jadi apakah versi integer saja merupakan persyaratan yang pasti? Saya tidak berpikir Swagger mendukung tipe enum dengan nilai string dan integer.
Hux
1
Perilaku yang Anda harapkan tidak jelas, dapatkah Anda menjelaskan dengan lebih baik apa yang Anda inginkan untuk ditampilkan oleh Swagger UI dan apa yang ingin Anda POST / PUT ke API Web Anda dengan contoh?
Federico Dipuma
Selain itu, jika saya memiliki metode GET yang mengambil enum di url, saya ingin skema menggambarkannya sebagai string dalam daftar drop-down nilai yang disarankan
Mengapa validasi integer gagal? Jenisnya harus berupa enum dalam model dan pemformat media json akan menangani string atau int dengan benar. Jika Anda memperbarui pertanyaan dengan sebuah contoh, ini akan membantu kami memahami mengapa validasi gagal.
Hux
4
Jika itu adalah enum bendera, itu harus berupa numerik, kecuali Anda memiliki nilai enum yang ditentukan untuk setiap kemungkinan kombinasi tanda. Kacau bahwa kesombongan tidak menampilkan KEDUA nama dan nilai untuk setiap enum, dan sebaliknya menampilkan nomor saja (tidak berguna) atau nama saja (sekali lagi, tidak berguna untuk bendera yang harus ditentukan sebagai angka).
Triynko

Jawaban:

188

Dari dokumen :

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

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

Selain itu, jika Anda menginginkan perilaku ini hanya pada tipe dan properti tertentu, gunakan StringEnumConverter:

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

    [Required]
    [EnumDataType(typeof(Priority))]
    [JsonConverter(typeof(StringEnumConverter))]
    public Priority Priority {get; set;}
}
Xavero
sumber
5
ini tidak berhasil untuk saya. [EnumDataType (typeof (Priority))] [JsonConverter (typeof (StringEnumConverter))]
Lineker
@NH. ya, saya menggunakan newtonsoft.json
Lineker
@ Lineker, posting kesalahan Anda sebagai pertanyaan baru, mengikuti panduan ini: stackoverflow.com/help/mcve
NH.
Terima kasih! Saya pikir saya mungkin hanya meninggalkan komentar Anda dalam sumber terlalu #thiswilldothetrick
Simon_Weaver
5
DescribeAllEnumsAsStringsbekerja untuk properti objek dan bahkan parameter kueri pada tindakan pengontrol. Namun, menggunakan EnumDataTypeAttributedan JsonConverter(typeof(StringEnumConverter))tidak berhasil untuk saya.
disadap87
92

Untuk ASP.NET Core 3 dengan pustaka Microsoft JSON (System.Text.Json)

Di Startup.cs / ConfigureServices ():

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

Untuk ASP.NET Core 3 dengan pustaka Json.NET (Newtonsoft.Json)

Instal Swashbuckle.AspNetCore.Newtonsoftpaketnya.

Di Startup.cs / ConfigureServices ():

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

Untuk ASP.NET Core 2

Di Startup.cs / ConfigureServices ():

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

Pra-ASP.NET Core

httpConfiguration
    .EnableSwagger(c => 
        {
            c.DescribeAllEnumsAsStrings();
        });
Lee Richardson
sumber
4
Masalah menggunakan options.SerializerSettings.Converters.Add (new StringEnumConverter ())) adalah bahwa Anda mengubah json untuk semua metode Anda, tidak hanya untuk Sawshbuckle.
Guillaume
Apakah ada yang punya solusi untuk Azure Functions v2 dan / atau v3?
Dan Friedman
@DanFriedman Mengingat Swashbuckle tidak berfungsi sama sekali dengan Fungsi Azure, Anda kurang beruntung.
Ian Kemp
@IanKemp Ada dukungan pihak ketiga dengan AzureExtensions.Swashbucklepaket tetapi seperti @DanFriedman saya tidak bisa mendapatkan enum-to-string yang berfungsi seperti yang diharapkan
wolfyuk
40

Jadi saya pikir saya memiliki masalah yang sama. Saya mencari kesombongan untuk menghasilkan enum bersama dengan int -> string mapping. API harus menerima int. Kesombongan-ui kurang penting, yang saya inginkan adalah pembuatan kode dengan enum "nyata" di sisi lain (aplikasi android menggunakan retrofit dalam kasus ini).

Jadi dari penelitian saya ini pada akhirnya tampaknya menjadi batasan spesifikasi OpenAPI yang digunakan Swagger. Tidak mungkin menentukan nama dan nomor untuk enum.

Masalah terbaik yang saya temukan untuk diikuti adalah https://github.com/OAI/OpenAPI-Specification/issues/681 yang terlihat seperti "mungkin segera" tetapi kemudian Swagger harus diperbarui, dan dalam kasus saya Swashbuckle sebagai baik.

Untuk saat ini solusi saya adalah menerapkan filter dokumen yang mencari enum dan mengisi deskripsi yang relevan dengan konten enum.

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

                    //disable this
                    //c.DescribeAllEnumsAsStrings()

SwaggerAddEnumDescriptions.cs:

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

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

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

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

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

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

}

Ini menghasilkan sesuatu seperti berikut pada swagger-ui Anda, jadi setidaknya Anda bisa "melihat apa yang Anda lakukan": masukkan deskripsi gambar di sini

Rory
sumber
1
+1 Saya ingin menambahkan deskripsi ke enum (hanya untuk 'mendeskripsikan enum'), tidak pernah memikirkan ini. Saya sudah memiliki filter lain-lain, tetapi mencari sesuatu yang lebih 'organik', tetapi tidak ada dukungan. Kalau begitu, filter semuanya :)
NSGaga-kebanyakan-tidak aktif
Terima kasih! Saya menggunakan ini dalam proyek saya, tetapi memodifikasinya untuk bekerja dengan .NET Core. Saya menambahkan implementasi saya sebagai jawaban.
Gabriel Luci
27

ASP.NET Core 3.1

Untuk menghasilkan enum sebagai string menggunakan Newtonsoft JSON Anda harus secara eksplisit menambahkan dukungan Newtonsoft dengan menambahkan AddSwaggerGenNewtonsoftSupport()sebagai berikut:

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


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

Ini tersedia melalui paket baru Swashbuckle.AspNetCore.Newtonsoft,. Sepertinya semuanya berfungsi dengan baik tanpa paket ini selain dari dukungan konverter enum.

Roman Starkov
sumber
1
Ini membantu untuk menyiapkan konvensi ini secara global, tetapi jika Anda perlu menerapkan ini hanya untuk jenis enum tertentu, Anda perlu membaca masalah ini dengan cermat . TL; DR: Tidak mungkin menerapkan StringEnumConverter () baru ke properti saja, tetapi Anda bisa menerapkannya ke seluruh jenis enum.
A. Tretiakov
1
Saya kira jika kita berbicara tentang gotcha, itu juga tidak mungkin untuk menggunakan konverter yang sepenuhnya khusus. Swagger tidak menjalankan nilai enum melalui konverter kustom; itu hanya diakui StringEnumConvertersebagai kasus khusus.
Roman Starkov
22

Saya ingin menggunakan jawaban rory_za dalam aplikasi .NET Core, tetapi saya harus sedikit memodifikasinya agar berfungsi. Berikut adalah implementasi yang saya buat untuk .NET Core.

Saya juga mengubahnya sehingga tidak menganggap tipe yang mendasarinya adalah int, dan menggunakan baris baru di antara nilai-nilai agar lebih mudah dibaca.

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

Kemudian tambahkan ini ke ConfigureServicesmetode Anda di Startup.cs:

c.DocumentFilter<EnumDocumentFilter>();
Gabriel Luci
sumber
Mungkin untuk menghapus Enum: Array [6] yang muncul di bawah?
Softlion
4
Solusi hebat, tetapi ekstensi di DescribeEnumParametersproyek saya kosong. Saya harus melemparkan paramke NonBodyParameterdan memeriksa enum di sana:if (param is NonBodyParameter nbParam && nbParam.Enum?.Any() == true) { param.Description += DescribeEnum(nbParam.Enum); }
Rabban
Di proyek saya, Ekstensi juga kosong, menggunakan solusi @Rabban.
Carlos Beppler
1
@Rabban Saya memperbarui kode saya untuk menyertakannya. Bisakah Anda memverifikasi bahwa saya meletakkannya di tempat yang benar? Saya tidak memiliki masalah ini. Mungkin versi yang lebih baru mengubah banyak hal.
Gabriel Luci
@GabrielLuci Dikonfirmasi dan disetujui;)
Rabban
12

Dengan asp.net core 3

using System.Text.Json.Serialization;

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

Namun tampaknya Swashbuckle Versi 5.0.0-rc4 belum siap mendukungnya. Jadi kita perlu menggunakan opsi (usang) di file konfigurasi Swashbuckle sampai mendukung dan mencerminkannya seperti perpustakaan Newtonsoft.

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

Perbedaan antara jawaban ini dan jawaban lainnya hanya menggunakan pustaka Microsoft JSON, bukan Newtonsoft.

Bashir Momen
sumber
Hai @Bashir, apakah ada masalah swachbuckle untuk melacak kurangnya dukungan itu?
Bernard Vander Beken
Hai @ bernard-vander-beken, saya tidak melaporkannya tapi saya anggap ada. Itu bagus jika kita dapat menemukannya dan menambahkannya ke posting ini untuk pembaruan nanti.
Bashir Momen
10

.NET CORE 3.1 dan SWAGGER 5

jika Anda membutuhkan solusi sederhana untuk secara selektif membuat enum diteruskan sebagai string:

using System.Text.Json.Serialization;


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

Perhatikan, kami menggunakan System.Text.Json.Serializationnamespace, bukan Newtonsoft.Json!

VeganHunter
sumber
Yang ini berfungsi menunjukkan nilai yang tepat, dan juga berfungsi saat mengonversi nilai kembali ke enum. Perhatikan bahwa Anda perlu menambahkan paket NuGet System.Text.Json.
MovGP0
Itulah yang saya cari! Karena saya harus menggunakan string hanya untuk satu enum, dan DescribeAllEnumsAsStringsakan mengubah semua enum menjadi string.
Nilay
9

jika ada yang tertarik saya telah memodifikasi kode untuk bekerja dengannya

.NET CORE 3 dan Swagger V5

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

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

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

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

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

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

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

        return string.Join(", ", enumDescriptions.ToArray());
    }
}
Hosam Rehani
sumber
1
Ini hanya bekerja ketika jenis parameter persis enum ... bukan nullable enum, kumpulan enum dll. Periksa jawaban saya untuk kasus tersebut.
Matyas
4

Saya baru saja melakukan ini dan berfungsi dengan baik!

Startup.cs

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

Model.cs

public enum ColumnType {
  DATE = 0
}

swagger.json

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

Saya harap ini membantu Anda bagaimana ini membantu saya!

Rodrigo Béco
sumber
2
DescribeAllEnumsAsStringstidak digunakan lagi
Node.JS
4

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

}

dan di Startup.cs:

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

Hasil

ehsan rezaee
sumber
4
Sisi negatifnya adalah, ketika menjalankan permintaan, alih-alih hanya meneruskan representasi int (seperti 2 misalnya) dari nilai enum, API akan mendapatkan deskripsi lengkap sebagai nilai (seperti LogicError = 3), yang akan gagal sebagai permintaan buruk karena itu bukan nilai yang valid untuk enum.
Matyas
3

Varian saya untuk sengatan enum dengan nilai:

masukkan deskripsi gambar di sini

Konfigurasi Layanan:

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

Saring:

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

tulis kode di dalam Startup.cs

services.AddSwaggerGen(c => {
      c.DescribeAllEnumsAsStrings();
    });
ANJYR - KODEXPRESSION
sumber
2
Opsi ini tidak digunakan lagi di Swashbuckle. Direkomendasikan untuk menggunakan opsi ASP.NET Core dan kemudian Swashbuckle dapat menerapkannya.
Bashir Momen
2

Saya telah menemukan solusi yang bagus di sini:

@PauloVetor - menyelesaikannya menggunakan ShemaFilter seperti ini:

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

Dan di Startup.cs:

services.AddSwaggerGen(options =>
{
    options.SchemaFilter<EnumSchemaFilter>();
}
heliks-nebula
sumber
Anda juga harus memastikan bahwa Anda memperbarui model.Formatke "string"sebagaimana biasanya "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()))
anıl yıldırım
sumber
1
Ini menggunakan Newtonsoft daripada serialisasi inti JSON asp.net baru.
Bashir Momen
1

Saya telah mengubah jawaban Hosam Rehani untuk bekerja dengan nullable enum dan juga dengan kumpulan enum. Jawaban sebelumnya juga berfungsi hanya jika sebuah properti dinamai persis seperti tipenya. Semua masalah ini ditangani dalam kode di bawah ini.

Ia bekerja dengan .net core 3.x dan swagger 5.x.

ini bisa lebih efisien dengan tidak mencari jenis enum dua kali dalam beberapa kasus.

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

untuk menggunakan filter tambahkan c.DocumentFilter<SwaggerAddEnumDescriptions>();ke konfigurasi swagger di Startup.cs.

Matyas
sumber
0

SOLUSI ASP NET

Dalam dokumen api saya, satu enum masih ditampilkan sebagai int meskipun properti itu ditandai dengan StringEnumConverter. Kami tidak mampu menggunakan pengaturan global untuk semua enum yang disebutkan di atas. Menambahkan baris ini di SwaggerConfig memecahkan masalah:

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

Ada sejumlah kekurangan yang saya temukan di jawaban lain untuk apa yang kami cari, jadi saya pikir saya akan memberikan pendapat saya sendiri tentang ini. Kami menggunakan ASP.NET Core 3.1 dengan System.Text.Json, tetapi pendekatan kami berfungsi terlepas dari serializer JSON yang digunakan.

Tujuan kami adalah untuk menerima nilai string enum bertingkat unta yang lebih rendah di ASP.NET Core API serta mendokumentasikan hal yang sama di Swagger. Saat ini kami menggunakan [DataContract]dan [EnumMember], jadi pendekatannya adalah dengan mengambil nilai unta-unta yang lebih rendah dari properti nilai EnumMember dan menggunakannya secara keseluruhan.

Contoh enum kami:

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

Kami akan menggunakan nilai EnumMember di Swashbuckle dengan menggunakan ISchemaFilter seperti berikut ini:

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

Kami menggunakan paket NuGet pihak ketiga ( repo GitHub ) untuk memastikan bahwa skema penamaan ini juga digunakan di ASP.NET Core. Konfigurasikan di Startup.cs dalam ConfigureServices dengan:

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

Terakhir, kita perlu mendaftarkan ISchemaFilter di Swashbuckle, jadi tambahkan juga berikut ini di ConfigureServices ():

services.AddSwaggerGen(c => {
  c.SchemaFilter<DescribeEnumMemberValues>();
});
Xaniff
sumber
GetMembers()akan lebih baik jika GetMembers(BindingFlags.Static | BindingFlags.Public)membatasi hanya pada properti enum yang dinyatakan sebenarnya seperti "Biru". Saya juga mengadaptasi kasus "lain" untuk mengembalikan Anggota.Nama jika tidak ada [EnumMember]atribut.
pengguna2864740
0

Ini tidak mungkin dengan OpenAPI standar. Enum hanya dijelaskan dengan nilai stringnya.

Untungnya Anda dapat melakukannya dengan beberapa ekstensi non-standar yang digunakan oleh generator klien Anda.

NSwag mendukung x-enumNames

Dukungan AutoRest x-ms-enum.

Openapi-generator mendukung x-enum-varnames

Generator lain mungkin mendukung salah satu ekstensi ini atau memiliki ekstensi sendiri.

Untuk menghasilkan x-enumNamesNSwag, buat filter skema berikut:

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

Dan daftarkan sebagai:

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