Swagger UI Web Api Dokumentation Enums als Strings präsentieren?


106

Gibt es eine Möglichkeit, alle Aufzählungen als Zeichenfolgenwert in swagger anstelle ihres int-Werts anzuzeigen?

Ich möchte in der Lage sein, POST-Aktionen einzureichen und Aufzählungen entsprechend ihrem Zeichenfolgenwert zu setzen, ohne jedes Mal die Aufzählung überprüfen zu müssen.

Ich habe es versucht, DescribeAllEnumsAsStringsaber der Server empfängt dann Zeichenfolgen anstelle des Aufzählungswerts, nach dem wir nicht suchen.

Hat jemand das gelöst?

Bearbeiten:

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
Möchten Sie, dass das Schema den Wert als Zeichenfolge beschreibt und dann eine Ganzzahl an den Server sendet? JSON.net wird beide Werte gut verarbeiten. Ist die Nur-Integer-Version also eine bestimmte Anforderung? Ich glaube nicht, dass Swagger einen Aufzählungstyp sowohl mit dem String- als auch mit dem Integer-Wert unterstützt.
Hux

1
Ihr erwartetes Verhalten ist unklar. Können Sie anhand von Beispielen besser erklären, was die Swagger-Benutzeroberfläche anzeigen soll und was Sie an Ihre Web-API POST / PUT senden möchten?
Federico Dipuma

Wenn ich GET-Methoden habe, die eine Aufzählung in der URL enthalten, möchte ich, dass das Schema diese als Zeichenfolgen in der Dropdown-Liste der vorgeschlagenen Werte beschreibt

Warum schlägt die Ganzzahlüberprüfung fehl? Der Typ sollte eine Aufzählung im Modell sein und der json-Medienformatierer würde entweder eine Zeichenfolge oder int korrekt verarbeiten. Wenn Sie die Frage mit einem Beispiel aktualisieren, können wir besser verstehen, warum die Validierung fehlschlägt.
Hux

4
Wenn es sich um eine Flags-Aufzählung handelt, muss diese numerisch sein, es sei denn, Sie haben für jede mögliche Kombination von Flags Aufzählungswerte definiert. Es ist verrückt, dass Swagger nicht BEIDEN Namen und Wert für jede Aufzählung anzeigt, sondern nur Zahlen allein (nutzlos) oder Namen allein (wiederum nutzlos für Flags, die als Zahlen angegeben werden müssen).
Triynko

Antworten:


189

Aus den Dokumenten :

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

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

Wenn Sie dieses Verhalten nur für einen bestimmten Typ und eine bestimmte Eigenschaft wünschen, verwenden Sie den StringEnumConverter:

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

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

5
Das funktioniert bei mir nicht. [EnumDataType (typeof (Priority))] [JsonConverter (typeof (StringEnumConverter))]
Lineker

@ NH. Ja, ich habe newtonsoft.json
Lineker

@Lineker, senden Sie Ihren Fehler als neue Frage gemäß
NH.

Vielen Dank! Ich denke, ich könnte Ihren Kommentar auch in der Quelle hinterlassen #thiswilldothetrick
Simon_Weaver

5
DescribeAllEnumsAsStringsarbeitete für Objekteigenschaften und sogar für Abfrageparameter für Controller-Aktionen. Allerdings mit EnumDataTypeAttributeund JsonConverter(typeof(StringEnumConverter))hat bei mir nicht funktioniert.
Bugged87

86

Für ASP.Net Core 3 mit Newtonsoft JSON-Bibliothek

Swashbuckle.AspNetCore.NewtonsoftPaket installieren .

Dann in Startup.cs / ConfigureServices ():

services
    .AddControllersWithViews(...)
    .AddNewtonsoftJson(options => 
        options.SerializerSettings.Converters.Add(new StringEnumConverter()));
services.AddSwaggerGenNewtonsoftSupport();

Dies erfordert keinen Aufruf von options.DescribeAllEnumsAsStrings()AddSwaggerGen ().

Für ASP.Net Core 3 mit Microsoft JSON-Bibliothek

Siehe @ Bashirs Antwort im Grunde:

services
    .AddControllersWithViews(...)
    .AddJsonOptions(options => 
        options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));

Und wie er beschreibt, erfordert es derzeit options.DescribeAllEnumsAsStrings().

Für ASP.Net Core 2

In Startup.cs / ConfigureServices ():

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

Dies erfordert keinen Aufruf von options.DescribeAllEnumsAsStrings()AddSwaggerGen ().

Pre ASP.Net Core

Verwenden Sie den DescribeAllEnumsAsStrings()Ansatz aus der akzeptierten Antwort.


Es könnte schön sein, wenn Sie JsonStringEnumConverter anstelle von StringEnumConverter verwenden.
Bashir Momen

4
Das Problem bei der Verwendung von options.SerializerSettings.Converters.Add (neuer StringEnumConverter ()) besteht darin, dass Sie den json für alle Ihre Methoden ändern, nicht nur für Sawshbuckle.
Guillaume

25
Für ASP.Net Core 3 mit Newtonsoft JSON-Bibliothek ist ein zusätzlicher Aufruf erforderlich: services.AddSwaggerGenNewtonsoftSupport();und Swashbuckle.AspNetCore.NewtonsoftNuget-Paket
Konstantin

3
@KonstantinRyazantsev Danke! Beachten Sie, dass AddSwaggerGenNewtonsoftSupport()genannt werden muss , nach AddSwaggerGen oder es wird nicht funktionieren.
Boiethios

Hat jemand eine Lösung für Azure Functions v2 und / oder v3?
Dan Friedman

39

Ich glaube, ich habe ein ähnliches Problem. Ich suche nach Prahlerei, um Enums zusammen mit der int -> String-Zuordnung zu generieren. Die API muss den int akzeptieren. Die Prahlerei-UI ist weniger wichtig. Was ich wirklich will, ist die Codegenerierung mit einer "echten" Aufzählung auf der anderen Seite (in diesem Fall Android-Apps mit Nachrüstung).

Aus meiner Forschung scheint dies letztendlich eine Grenze der OpenAPI-Spezifikation zu sein, die Swagger verwendet. Es ist nicht möglich, Namen und Nummern für Aufzählungen anzugeben.

Das beste Problem, das ich gefunden habe, ist https://github.com/OAI/OpenAPI-Specification/issues/681, das wie "vielleicht bald" aussieht, aber dann müsste Swagger aktualisiert werden, und in meinem Fall Swashbuckle als Gut.

Im Moment bestand meine Problemumgehung darin, einen Dokumentfilter zu implementieren, der nach Aufzählungen sucht und die entsprechende Beschreibung mit dem Inhalt der Aufzählung füllt.

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

}

Dies führt auf Ihrer Swagger-Benutzeroberfläche zu folgenden Ergebnissen, sodass Sie zumindest "sehen können, was Sie tun": Geben Sie hier die Bildbeschreibung ein


1
+1 Ich wollte Beschreibungen zu Aufzählungen hinzufügen (nur um 'Aufzählung zu beschreiben'), habe nie daran gedacht. Ich habe bereits verschiedene Filter installiert, suchte aber nach etwas „Organischerem“, aber es gibt keine Unterstützung. Na dann, Filter den ganzen Weg :)
NSGaga-meistens-inaktiv

Vielen Dank! Ich habe dies in meinem Projekt verwendet, es jedoch so geändert, dass es mit .NET Core funktioniert. Ich habe meine Implementierung als Antwort hinzugefügt.
Gabriel Luci

28

ASP.NET Core 3.1

Um mit Newtonsoft JSON Aufzählungen als Zeichenfolgen zu generieren, müssen Sie die Newtonsoft-Unterstützung explizit hinzufügen, indem Sie AddSwaggerGenNewtonsoftSupport()Folgendes hinzufügen :

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


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

Dies ist über ein neues Paket möglich Swashbuckle.AspNetCore.Newtonsoft. Es sieht so aus, als ob alles andere ohne dieses Paket gut funktioniert, abgesehen von der Unterstützung von Enum Converter.


1
Es ist hilfreich, diese Konvention global einzurichten. Wenn Sie dies jedoch nur auf bestimmte Arten von Aufzählungen anwenden müssen, müssen Sie dieses Problem sorgfältig lesen . TL; DR: Es ist nicht möglich, neuen StringEnumConverter () nur auf Eigenschaften anzuwenden, aber Sie können ihn auf den gesamten Aufzählungstyp anwenden.
A. Tretiakov

1
Ich nehme an, wenn es sich um Fallstricke handelt, ist es auch nicht möglich, einen vollständig benutzerdefinierten Konverter zu verwenden. Swagger führt die Enum-Werte nicht über den benutzerdefinierten Konverter aus. es erkennt einfach StringEnumConverterals Sonderfall.
Roman Starkov

22

Ich wollte die Antwort von rory_za in einer .NET Core-Anwendung verwenden, musste sie jedoch ein wenig ändern, damit sie funktioniert. Hier ist die Implementierung, die ich für .NET Core entwickelt habe.

Ich habe es auch geändert, damit nicht angenommen wird int, dass es sich um den zugrunde liegenden Typ handelt , und neue Zeilen zwischen den Werten verwendet, um das Lesen zu erleichtern.

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

Fügen Sie dies dann Ihrer ConfigureServicesMethode in Startup.cs hinzu:

c.DocumentFilter<EnumDocumentFilter>();

Kann das unten angezeigte Enum: Array [6] entfernt werden?
Softlion

4
Tolle Lösung, aber die Erweiterungen in DescribeEnumParameterswaren in meinem Projekt leer. Ich musste das paramzu NonBodyParameterbesetzen und die Aufzählung dort überprüfen:if (param is NonBodyParameter nbParam && nbParam.Enum?.Any() == true) { param.Description += DescribeEnum(nbParam.Enum); }
Rabban

In meinem Projekt ist Extensions auch leer, verwendet die @ Rabban-Lösung.
Carlos Beppler

1
@ Rabban Ich habe meinen Code aktualisiert, um das einzuschließen. Können Sie einfach überprüfen, ob ich es an der richtigen Stelle platziert habe? Ich hatte dieses Problem nicht. Vielleicht hat eine neuere Version die Dinge geändert.
Gabriel Luci

@ GabrielLuci Bestätigt und genehmigt;)
Rabban

12

Mit asp.net Kern 3

using System.Text.Json.Serialization;

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

Aber es scheint, dass Swashbuckle Version 5.0.0-rc4 nicht bereit ist, dies zu unterstützen. Daher müssen wir eine Option (veraltet) in der Swashbuckle-Konfigurationsdatei verwenden, bis sie wie die Newtonsoft-Bibliothek unterstützt und wiedergegeben wird.

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

Der Unterschied zwischen dieser Antwort und anderen Antworten besteht darin, dass nur die Microsoft JSON-Bibliothek anstelle von Newtonsoft verwendet wird.


Hey @Bashir, gibt es ein Problem mit dem Swachbuckle, um den Mangel an dieser Unterstützung im Auge zu behalten?
Bernard Vander Beken

Hallo @ bernard-vander-beken, das habe ich nicht gemeldet, aber ich gehe davon aus, dass es das gibt. Es ist gut, wenn wir es finden und diesem Beitrag für spätere Updates hinzufügen können.
Bashir Momen


10

.NET CORE 3.1 und SWAGGER 5

Wenn Sie eine einfache Lösung benötigen, um selektiv als Zeichenfolgen übergebene Aufzählungen zu erstellen:

using System.Text.Json.Serialization;


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

Beachten Sie, dass wir den System.Text.Json.SerializationNamespace verwenden, nicht den Newtonsoft.Json!


Dieser zeigt die richtigen Werte an und funktioniert auch, wenn die Werte wieder in die Aufzählung konvertiert werden. Beachten Sie, dass Sie das NuGet-Paket hinzufügen müssen System.Text.Json.
MovGP0

Das habe ich gesucht! Da ich String nur für eine einzelne Aufzählung verwenden muss und DescribeAllEnumsAsStringsalle Aufzählungen in den String konvertieren werde.
Nilay

9

Wenn jemand interessiert ist, habe ich den Code geändert, um damit zu arbeiten

.NET CORE 3 und 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
Dies funktioniert nur, wenn der Parametertyp genau enum ist ... nicht nullable enum, Sammlung von Aufzählungen usw. Überprüfen Sie meine Antwort für diese Fälle.
Matyas

4

Ich habe das gerade gemacht und es funktioniert gut!

Startup.cs

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

Model.cs

public enum ColumnType {
  DATE = 0
}

swagger.json

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

Ich hoffe das hilft dir wie es mir geholfen hat!


2
DescribeAllEnumsAsStringsist veraltet
Node.JS

4

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

}

und in Startup.cs:

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

Ergebnis


4
Der Nachteil dabei ist, dass die API beim Ausführen einer Anforderung nicht nur die int-Darstellung (wie z. B. 2) eines Enum-Werts übergibt, sondern die vollständige Beschreibung als Wert (wie LogicError = 3) erhält, was als Fehler fehlschlägt schlechte Anfrage, da es kein gültiger Wert für die Aufzählung ist.
Matyas

3

Meine Variante für Enum Stings mit Werten:

Geben Sie hier die Bildbeschreibung ein

Dienste konfigurieren:

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

Filter:

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

Schreiben Sie Code in Startup.cs

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

2
Diese Option ist im Swashbuckle veraltet. Es wird empfohlen, die Option ASP.NET Core zu verwenden, und dann kann Swashbuckle dies widerspiegeln.
Bashir Momen

1

.Net Core 3.0

   using Newtonsoft.Json.Converters;

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

1
Es wird Newtonsoft anstelle der neuen asp.net-Kern-JSON-Serialisierung verwendet.
Bashir Momen

1

Ich habe hier eine gute Lösung gefunden:

@PauloVetor - löste es mit ShemaFilter wie folgt:

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

Und in Startup.cs:

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

Sie sollten auch sicherstellen, dass Sie das aktualisieren model.Format, "string"wie es im Allgemeinen sein wird "int32".
lsuarez

1

Ich habe Hosam Rehanis Antwort geändert, um mit nullbaren Aufzählungen und auch mit der Sammlung von Aufzählungen zu arbeiten. Die vorherige Antwort funktioniert auch nur, wenn eine Eigenschaft genau wie ihr Typ benannt ist. All diese Probleme werden im folgenden Code behandelt.

Es funktioniert mit .net Core 3.x und Swagger 5.x.

Es könnte effizienter sein, wenn in einigen Fällen nicht zweimal nach dem Aufzählungstyp gesucht wird.

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

Um den Filter zu verwenden, fügen Sie c.DocumentFilter<SwaggerAddEnumDescriptions>();die Swagger-Konfiguration hinzu Startup.cs.


0

ASP-NETZLÖSUNG

In meinen API-Dokumenten wurde eine Aufzählung immer noch als int angezeigt, obwohl die Eigenschaft mit markiert ist StringEnumConverter. Wir konnten es uns nicht leisten, die globale Einstellung für alle oben genannten Aufzählungen zu verwenden. Das Hinzufügen dieser Zeile in SwaggerConfig löste das Problem:

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

0

Es gab eine Reihe von Mängeln, die ich in den anderen Antworten für das gefunden habe, wonach wir gesucht haben, also dachte ich, ich würde meine eigene Meinung dazu abgeben. Wir verwenden ASP.NET Core 3.1 mit System.Text.Json, aber unser Ansatz funktioniert unabhängig vom verwendeten JSON-Serializer.

Unser Ziel war es, Enum-String-Werte mit niedrigerer Kamelhülle sowohl in der ASP.NET Core-API als auch in Swagger zu dokumentieren. Wir verwenden derzeit [DataContract]und [EnumMember], daher besteht der Ansatz darin, den Wert mit niedrigerer Kamelhülle aus der EnumMember-Werteigenschaft zu übernehmen und auf der ganzen Linie zu verwenden.

Unsere Beispielaufzählung:

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

Wir werden die EnumMember-Werte in Swashbuckle verwenden, indem wir einen ISchemaFilter wie folgt verwenden:

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

Wir verwenden ein NuGet-Paket eines Drittanbieters (GitHub- Repo ), um sicherzustellen, dass dieses Namensschema auch in ASP.NET Core verwendet wird. Konfigurieren Sie es in Startup.cs in ConfigureServices mit:

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

Schließlich müssen wir unseren ISchemaFilter in Swashbuckle registrieren, also fügen Sie auch in ConfigureServices () Folgendes hinzu:

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

GetMembers()Es wäre besser GetMembers(BindingFlags.Static | BindingFlags.Public), sich nur auf die tatsächlich deklarierten Enum-Eigenschaften wie "Blau" zu beschränken. Ich habe auch den Fall "else" angepasst, um den Member.Name zurückzugeben, wenn kein [EnumMember]Attribut vorhanden ist.
user2864740

0

Dies ist mit Standard-OpenAPI nicht möglich. Aufzählungen werden nur mit ihren Zeichenfolgenwerten beschrieben.

Glücklicherweise können Sie dies mit einigen nicht standardmäßigen Erweiterungen tun, die von Ihrem Client-Generator verwendet werden.

NSwag unterstützt x-enumNames

AutoRest unterstützt x-ms-enum.

Openapi-Generator unterstützt x-enum-varnames

Andere Generatoren unterstützen möglicherweise eine dieser Erweiterungen oder haben ihre eigene.

Um x-enumNamesfür NSwag zu generieren, erstellen Sie den folgenden Schemafilter:

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

Und registrieren Sie es als:

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.