Swagger UI Web Apiドキュメント列挙型を文字列として提示しますか?


107

すべての列挙型を、int値ではなくswaggerで文字列値として表示する方法はありますか?

毎回列挙型を確認しなくても、POSTアクションを送信し、文字列値に従って列挙型を配置できるようにしたいと考えています。

私は試しましたDescribeAllEnumsAsStringsが、サーバーは列挙値の代わりに文字列を受け取りますが、これは私たちが探しているものではありません。

誰かがこれを解決しましたか?

編集:

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

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


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

        ..
    }

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

    }
}


public enum Priority
{
    Low, 
    Medium,
    High
}

1
スキーマで値を文字列として記述し、サーバーに整数をポストしますか?JSON.netは両方の値を適切に処理するので、整数のみのバージョンは明確な要件ですか?Swaggerが文字列値と整数値の両方を持つ列挙型をサポートしているとは思いません。
HUX

1
予想される動作が不明確です。SwaggerUIに何を表示させ、何をWebAPIにPOST / PUTさせたいかについて、例を挙げて説明してください。
フェデリコディプマ

さらに、URLで列挙型を取得するGETメソッドがある場合は、スキームが推奨値のドロップダウンリストで文字列としてそれを説明するようにしたい

整数の検証が失敗するのはなぜですか?タイプはモデルの列挙型である必要があり、jsonメディアフォーマッターは文字列またはintを正しく処理します。例で質問を更新すると、検証が失敗した理由を理解するのに役立ちます。
Hux

4
フラグの列挙型の場合は、可能なすべてのフラグの組み合わせに対して列挙型の値を定義していない限り、数値でなければなりません。swaggerが各列挙型の名前と値の両方を表示せず、代わりに数値のみ(役に立たない)または名前のみ(ふたたび、数値として指定する必要があるフラグには役に立たない)を表示するのはおかしなことです。
Triynko 2018

回答:


188

ドキュメントから:

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

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

また、特定のタイプとプロパティでのみこの動作が必要な場合は、StringEnumConverterを使用します。

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

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

5
これは私にとっては機能しません。[EnumDataType(typeof(Priority))] [JsonConverter(typeof(StringEnumConverter))]
Lineker

@NH。はい、newtonsoft.jsonを使用しました
Lineker

:@Linekerは、このガイドに続いて、新しい質問としてあなたのエラーを投稿stackoverflow.com/help/mcve
NH。

どうも!私もあなたのコメントをソースに残すかもしれないと思います#thiswilldothetrick
Simon_Weaver

5
DescribeAllEnumsAsStringsオブジェクトのプロパティやコントローラーアクションのクエリパラメーターでさえ機能しました。ただし、使用するEnumDataTypeAttributeJsonConverter(typeof(StringEnumConverter))私のために動作しませんでした。
bugged87

88

Microsoft JSONライブラリ(System.Text.Json)を備えたASP.NET Core 3の場合

Startup.cs / ConfigureServices()で:

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

Json.NET(Newtonsoft.Json)ライブラリを備えたASP.NET Core 3の場合

Swashbuckle.AspNetCore.Newtonsoftパッケージをインストールします。

Startup.cs / ConfigureServices()で:

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

ASP.NET Core 2の場合

Startup.cs / ConfigureServices()で:

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

ASP.NET以前のコア

httpConfiguration
    .EnableSwagger(c => 
        {
            c.DescribeAllEnumsAsStrings();
        });

4
options.SerializerSettings.Converters.Add(new StringEnumConverter()))を使用する際の問題は、Sawshbuckleだけでなく、すべてのメソッドのjsonを変更することです。
ギヨーム

Azure Functions v2またはv3、あるいはその両方のソリューションを持っている人はいますか?
Dan Friedman

@DanFriedman SwashbuckleがAzure Functionsでまったく機能しないことを考えると、あなたは運が悪いです。
Ian Kemp

@IanKemp AzureExtensions.Swashbuckleパッケージにはサードパーティのサポートがありますが、@ DanFriedmanのように、enum-to-stringが期待どおりに機能しません
wolfyuk

40

だから私は同様の問題があると思います。私は、int-> stringマッピングとともに列挙型を生成するswaggerを探しています。APIはintを受け入れる必要があります。swagger-uiはそれほど重要ではありません。私が本当に望んでいるのは、反対側に「実際の」列挙型を使用したコード生成です(この場合、レトロフィットを使用するAndroidアプリ)。

したがって、私の研究から、これは最終的にSwaggerが使用するOpenAPI仕様の制限のようです。列挙型の名前と番号を指定することはできません。

私がフォローしていることがわかった最良の問題はhttps://github.com/OAI/OpenAPI-Specification/issues/681ですこれは「もうすぐ」のように見えますが、Swaggerを更新する必要があり、私の場合はSwashbuckleとして上手。

当面の回避策は、列挙型を探し、関連する説明に列挙型の内容を入力するドキュメントフィルターを実装することです。

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

                    //disable this
                    //c.DescribeAllEnumsAsStrings()

SwaggerAddEnumDescriptions.cs:

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

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

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

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

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

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

}

これにより、swagger-uiに次のような結果が表示されるため、少なくとも「何をしているか」を確認できます。 ここに画像の説明を入力してください


1
+1私は列挙型に説明を追加しようとしていましたが(「列挙型を記述する」ため)、これについては考えていませんでした。すでにその他のフィルターを使用していますが、より「オーガニック」なものを探していましたが、サポートがありませんでした。それでは、ずっとフィルターをかけます:)
NSGaga-mostly-active 17/11/16

ありがとう!これをプロジェクトで使用しましたが、.NET Coreで動作するように変更しました。実装を回答として追加しました。
Gabriel Luci

27

ASP.NET Core 3.1

Newtonsoft JSONを使用して列挙型を文字列として生成するにはAddSwaggerGenNewtonsoftSupport()、次のように追加してNewtonsoftサポートを明示的に追加する必要があります。

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


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

これは新しいパッケージで利用できますSwashbuckle.AspNetCore.Newtonsoft。enumコンバーターのサポートを除いて、このパッケージなしで他のすべてが正常に動作するようです。


1
この規則をグローバルに設定するのに役立ちますが、これを特定のタイプの列挙型にのみ適用する必要がある場合は、この問題を注意深く読む必要があります。TL; DR:新しいStringEnumConverter()をプロパティのみに適用することはできませんが、列挙型全体に適用できます。
A.

1
私たちが落とし穴について話しているとしたら、完全にカスタムなコンバーターを使用することも不可能だと思います。Swaggerはカスタムコンバーターを通じて列挙値を実行しません。単にStringEnumConverter特殊なケースとして認識されます。
ロマン・スターコフ

22

.NET Coreアプリケーションでrory_zaの回答を使用したかったのですが、機能させるために少し変更する必要がありました。これが私が.NET Coreのために思いついた実装です。

また、基になるタイプがintであると想定しないように変更し、読みやすくするために値の間に改行を使用しています。

/// <summary>
/// Add enum value descriptions to Swagger
/// </summary>
public class EnumDocumentFilter : IDocumentFilter {
    /// <inheritdoc />
    public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context) {
        // add enum descriptions to result models
        foreach (var schemaDictionaryItem in swaggerDoc.Definitions) {
            var schema = schemaDictionaryItem.Value;
            foreach (var propertyDictionaryItem in schema.Properties) {
                var property = propertyDictionaryItem.Value;
                var propertyEnums = property.Enum;
                if (propertyEnums != null && propertyEnums.Count > 0) {
                    property.Description += DescribeEnum(propertyEnums);
                }
            }
        }

        if (swaggerDoc.Paths.Count <= 0) return;

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

            // head, patch, options, delete left out
            var possibleParameterisedOperations = new List<Operation> {pathItem.Get, pathItem.Post, pathItem.Put};
            possibleParameterisedOperations.FindAll(x => x != null)
                .ForEach(x => DescribeEnumParameters(x.Parameters));
        }
    }

    private static void DescribeEnumParameters(IList<IParameter> parameters) {
        if (parameters == null) return;

        foreach (var param in parameters) {
            if (param is NonBodyParameter nbParam && nbParam.Enum?.Any() == true) {
                param.Description += DescribeEnum(nbParam.Enum);
            } else if (param.Extensions.ContainsKey("enum") && param.Extensions["enum"] is IList<object> paramEnums &&
                paramEnums.Count > 0) {
                param.Description += DescribeEnum(paramEnums);
            }
        }
    }

    private static string DescribeEnum(IEnumerable<object> enums) {
        var enumDescriptions = new List<string>();
        Type type = null;
        foreach (var enumOption in enums) {
            if (type == null) type = enumOption.GetType();
            enumDescriptions.Add($"{Convert.ChangeType(enumOption, type.GetEnumUnderlyingType())} = {Enum.GetName(type, enumOption)}");
        }

        return $"{Environment.NewLine}{string.Join(Environment.NewLine, enumDescriptions)}";
    }
}

次に、これをConfigureServicesStartup.csのメソッドに追加します。

c.DocumentFilter<EnumDocumentFilter>();

以下に表示されるEnum:Array [6]を削除できますか?
Softlion、2018

4
素晴らしいソリューションですが、DescribeEnumParameters私のプロジェクトではの拡張機能は空でした。私はtoをキャストしparamNonBodyParameterそこで列挙型をチェックしなければなりませんでした:if (param is NonBodyParameter nbParam && nbParam.Enum?.Any() == true) { param.Description += DescribeEnum(nbParam.Enum); }
Rabban

私のプロジェクトでは拡張機能も空です。@ Rabbanソリューションを使用しました。
Carlos Beppler、

1
@Rabbanそれを含めるようにコードを更新しました。私が正しい場所に置いたことを確認できますか?この問題はありませんでした。新しいバージョンで状況が変わったのかもしれません。
Gabriel Luci

@GabrielLuci確認および承認済み;)
Rabban

12

asp.netコア3

using System.Text.Json.Serialization;

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

しかし、Swashbuckleバージョン5.0.0-rc4はそれをサポートする準備ができていないようです。したがって、Newtonsoftライブラリのようにサポートおよび反映されるまで、Swashbuckle構成ファイルでオプション(非推奨)を使用する必要があります。

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

この回答と他の回答の違いは、NewtonsoftではなくMicrosoft JSONライブラリのみを使用していることです。


@Bashirさん、サポートの欠如を追跡するためのswachbuckleの問題はありますか?
Bernard Vander Beken

こんにちは@ bernard-vander-beken、私はそれを報告しませんでしたが、あると思います。それを見つけて、後で更新するためにこの投稿に追加できるとよいでしょう。
バシルMomen


10

.NET CORE 3.1およびSWAGGER 5

列挙型を選択的に文字列として渡す簡単なソリューションが必要な場合:

using System.Text.Json.Serialization;


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

注:!System.Text.Json.Serializationではなく名前空間を使用しますNewtonsoft.Json


これは適切な値を表示して機能し、値を変換して列挙型に戻すときにも機能します。NuGetパッケージを追加する必要があることに注意してくださいSystem.Text.Json
MovGP0

それが私が探していたものです!私は単一の列挙DescribeAllEnumsAsStrings型に文字列を使用する必要があるため、すべての列挙型を文字列に変換します。
Nilay

9

誰かが興味を持っているなら、私は動作するようにコードを変更しました

.NET CORE 3およびSwagger V5

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

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

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

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

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

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

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

        return string.Join(", ", enumDescriptions.ToArray());
    }
}

1
これは、パラメーターの型が正確に列挙型である場合にのみ機能します。null許容列挙型、列挙型のコレクションなどではありません。これらのケースについては、私の答えを確認してください。
Matyas

4

私はこれをやっただけでうまくいきます!

Startup.cs

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

Model.cs

public enum ColumnType {
  DATE = 0
}

swagger.json

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

これが私をどのように助けてくれたのかお役に立てば幸いです!


2
DescribeAllEnumsAsStringsは非推奨
Node.JS

4

.net core 3.1およびswagger 5.0.0の場合:

using System.Linq;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace WebFramework.Swagger
{
    public class EnumSchemaFilter : ISchemaFilter
    {
        public void Apply(OpenApiSchema schema, SchemaFilterContext context)
        {
            if (context.Type.IsEnum)
            {
                var enumValues = schema.Enum.ToArray();
                var i = 0;
                schema.Enum.Clear();
                foreach (var n in Enum.GetNames(context.Type).ToList())
                {
                    schema.Enum.Add(new OpenApiString(n + $" = {((OpenApiPrimitive<int>)enumValues[i]).Value}"));
                    i++;
                }
            }
        }
    }

}

およびStartup.csで:

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

結果


4
これの欠点は、リクエストを実行するときに、列挙値のint表現(2など)のみを渡すのではなく、APIが完全な説明を(LogicError = 3などの)値として取得することです。 enumの有効な値ではないため、リクエストは正しくありません。
Matyas

3

値を持つ列挙文字列の私のバリアント:

ここに画像の説明を入力してください

サービスの構成:

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

フィルタ:

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

2

Startup.cs内にコードを記述する

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

2
このオプションはスワッシュバックルで廃止されました。ASP.NET Coreオプションを使用することをお勧めします。そうすると、Swashbuckleがそれを反映できます。
Bashir Momen

2

私はここに良い回避策を見つけました:

@PauloVetor-このようにShemaFilterを使用して解決しました:

public class EnumSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema model, SchemaFilterContext context)
    {
        if (context.Type.IsEnum)
        {
            model.Enum.Clear();
            Enum.GetNames(context.Type)
                .ToList()
                .ForEach(n => model.Enum.Add(new OpenApiString(n)));
            }
        }
    }
}

そして、Startup.cs:

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

また、あなたが更新することを確認する必要がありますmodel.Format"string"、それは一般的になるように"int32"
lsuarez

1

.Net Core 3.0

   using Newtonsoft.Json.Converters;

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

1
新しいasp.netコアJSONシリアル化の代わりにNewtonsoftを使用しています。
Bashir Momen

1

Hosam Rehaniの回答を変更して、null可能列挙型と列挙型のコレクションも処理できるようにしました。前の回答は、プロパティがそのタイプとまったく同じように名前が付けられている場合にのみ機能します。これらの問題はすべて、以下のコードで対処されています。

.netコア3.xおよびswagger 5.xで動作します。

場合によっては、列挙型を2回検索しない方が効率的です。

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

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

    private void DescribeEnumParameters(IDictionary<OperationType, OpenApiOperation> operations, OpenApiDocument swaggerDoc, IEnumerable<ApiDescription> apiDescriptions, string path)
    {
        path = path.Trim('/');
        if (operations != null)
        {
            var pathDescriptions = apiDescriptions.Where(a => a.RelativePath == path);
            foreach (var oper in operations)
            {
                var operationDescription = pathDescriptions.FirstOrDefault(a => a.HttpMethod.Equals(oper.Key.ToString(), StringComparison.InvariantCultureIgnoreCase));
                foreach (var param in oper.Value.Parameters)
                {
                    var parameterDescription = operationDescription.ParameterDescriptions.FirstOrDefault(a => a.Name == param.Name);
                    if (parameterDescription != null && TryGetEnumType(parameterDescription.Type, out Type enumType))
                    {
                        var paramEnum = swaggerDoc.Components.Schemas.FirstOrDefault(x => x.Key == enumType.Name);
                        if (paramEnum.Value != null)
                        {
                            param.Description += DescribeEnum(paramEnum.Value.Enum, paramEnum.Key);
                        }
                    }
                }
            }
        }
    }

    bool TryGetEnumType(Type type, out Type enumType)
    {
        if (type.IsEnum)
        {
            enumType = type;
            return true;
        }
        else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
        {
            var underlyingType = Nullable.GetUnderlyingType(type);
            if (underlyingType != null && underlyingType.IsEnum == true)
            {
                enumType = underlyingType;
                return true;
            }
        }
        else
        {
            Type underlyingType = GetTypeIEnumerableType(type);
            if (underlyingType != null && underlyingType.IsEnum)
            {
                enumType = underlyingType;
                return true;
            }
            else
            {
                var interfaces = type.GetInterfaces();
                foreach (var interfaceType in interfaces)
                {
                    underlyingType = GetTypeIEnumerableType(interfaceType);
                    if (underlyingType != null && underlyingType.IsEnum)
                    {
                        enumType = underlyingType;
                        return true;
                    }
                }
            }
        }

        enumType = null;
        return false;
    }

    Type GetTypeIEnumerableType(Type type)
    {
        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
        {
            var underlyingType = type.GetGenericArguments()[0];
            if (underlyingType.IsEnum)
            {
                return underlyingType;
            }
        }

        return null;
    }

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

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

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

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

        return string.Join(", ", enumDescriptions.ToArray());
    }
}

フィルタを使用するには、でc.DocumentFilter<SwaggerAddEnumDescriptions>();Swagger設定に追加しますStartup.cs


0

ASP NETソリューション

私のAPIドキュメントでは、プロパティがでマークされているにもかかわらず、1つの列挙型が引き続きintとして表示されていましたStringEnumConverter。上記のすべての列挙型にグローバル設定を使用する余裕はありませんでした。SwaggerConfigにこの行を追加すると、問題が解決しました:

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

0

私たちが探していたものについて、他の回答で見つけたいくつかの欠点があったので、私はこれについて私自身の見解を提供すると思いました。System.Text.JsonでASP.NET Core 3.1を使用していますが、使用するJSONシリアライザーに関係なく、このアプローチは機能します。

私たちの目標は、ASP.NET Core APIの両方で小文字のキャメルケースの列挙文字列値を受け入れることと、Swaggerで同じことを文書化することでした。我々は現在の使用を作っている[DataContract][EnumMember]、そのアプローチは軒並みことEnumMember値プロパティおよび使用から低キャメルケース値を取ることです。

サンプル列挙型:

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

次のようにISchemaFilterを使用して、スワッシュバックルのEnumMember値を使用します。

public class DescribeEnumMemberValues : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        if (context.Type.IsEnum)
        {
            schema.Enum.Clear();

            //Retrieve each of the values decorated with an EnumMember attribute
            foreach (var member in context.Type.GetMembers())
            {
                var memberAttr = member.GetCustomAttributes(typeof(EnumMemberAttribute), false).FirstOrDefault();
                if (memberAttr != null)
                {
                    var attr = (EnumMemberAttribute) memberAttr;
                    schema.Enum.Add(new OpenApiString(attr.Value));
                }
            }
        }
    }
}

私たちは、使用しているサードパーティのNuGetパッケージ(のGitHub のレポをこの命名スキームはまた、ASP.NETコアで利用されていることを確認します)。以下を使用して、ConfigureServices内のStartup.csで構成します。

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

最後に、ISchemaFilterをSwashbuckleに登録する必要があるため、ConfigureServices()にも以下を追加します。

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

GetMembers()GetMembers(BindingFlags.Static | BindingFlags.Public)「Blue」などの実際に宣言された列挙型プロパティのみに制限する方が良いでしょう。また、[EnumMember]属性がない場合はMember.Nameを返すように「else」ケースを調整しました。
user2864740

0

これは、標準のOpenAPIでは不可能です。列挙型は、その文字列値でのみ説明されます。

幸い、クライアントジェネレーターで利用される非標準の拡張機能を使用してそれを行うことができます。

NSwagのサポート x-enumNames

AutoRestはをサポートしていますx-ms-enum

Openapi-generatorのサポート x-enum-varnames

他のジェネレーターは、これらの拡張機能の1つをサポートするか、独自の拡張機能を持つ場合があります。

x-enumNamesNSwag を生成するには、次のスキーマフィルターを作成します。

public class EnumSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        if (context.Type.IsEnum)
        {
            var array = new OpenApiArray();
            array.AddRange(Enum.GetNames(context.Type).Select(n => new OpenApiString(n)));
            // NSwag
            schema.Extensions.Add("x-enumNames", array);
            // Openapi-generator
            schema.Extensions.Add("x-enum-varnames", array);
        }
    }
}

次のように登録します。

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.