Swagger UI Web Api 문서 열거 형을 문자열로 표시합니까?


107

모든 enum을 int 값 대신 swagger의 문자열 값으로 표시하는 방법이 있습니까?

매번 enum을 보지 않고도 POST 작업을 제출하고 문자열 값에 따라 enum을 넣을 수 있기를 원합니다.

시도 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
예상되는 동작이 명확하지 않습니다. Swagger UI에 표시 할 내용과 예제를 통해 웹 API에 POST / PUT하려는 내용을 더 잘 설명 할 수 있습니까?
Federico Dipuma

또한 URL에 열거 형을 사용하는 GET 메서드가있는 경우 제안 된 값의 드롭 다운 목록에있는 문자열로 설명하기를

정수 유효성 검사가 실패하는 이유는 무엇입니까? 유형은 모델의 열거 형이어야하며 json 미디어 포맷터는 문자열 또는 정수를 올바르게 처리합니다. 예제로 질문을 업데이트하면 유효성 검사가 실패한 이유를 이해하는 데 도움이됩니다.
Hux 2016-04-08

4
플래그 열거 형인 경우 가능한 모든 플래그 조합에 대해 열거 형 값을 정의하지 않는 한 숫자 여야합니다. swagger는 각 열거 형의 이름과 값을 모두 표시하지 않고 대신 숫자 만 표시하거나 (쓸모 없음) 이름 만 표시합니다 (다시 말하지만 숫자로 지정해야하는 플래그에는 쓸모가 없습니다).
Triynko

답변:


188

에서 워드 프로세서 :

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

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

또한 특정 유형 및 속성에서만이 동작을 원하면 StringEnumConverter를 사용합니다.

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

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

5
이것은 나를 위해 작동하지 않습니다 [EnumDataType (대해서 typeof (우선 순위))] [JsonConverter (대해서 typeof (StringEnumConverter))].
리네 커

@NH. 예, 저는 newtonsoft.json을 사용했습니다
Lineker

@Lineker,이 가이드에 따라 새 질문으로 오류를 게시하십시오. stackoverflow.com/help/mcve
NH.

고마워! 난 그냥 너무 #thiswilldothetrick 소스에 댓글을 남기 것 같아요
Simon_Weaver

5
DescribeAllEnumsAsStrings개체 속성 및 컨트롤러 작업에 대한 쿼리 매개 변수에 대해서도 작업했습니다. 그러나 사용 EnumDataTypeAttribute하고 JsonConverter(typeof(StringEnumConverter))나를 위해 작동하지 않았습니다.
bugged87

91

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 Core 이전

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

4
options.SerializerSettings.Converters.Add (new StringEnumConverter ())) 사용 문제는 Sawshbuckle뿐만 아니라 모든 메서드에 대한 json을 변경하는 것입니다.
Guillaume

누구든지 Azure Functions v2 및 / 또는 v3에 대한 솔루션이 있습니까?
Dan Friedman

@DanFriedman Swashbuckle이 Azure Functions에서 전혀 작동하지 않는다고 생각하면 운이 좋지 않습니다.
Ian Kemp

@IanKemp AzureExtensions.Swashbuckle패키지 에 대한 타사 지원이 있지만 @DanFriedman처럼 예상대로 enum-to-string이 작동하지 않습니다
wolfyuk

40

그래서 비슷한 문제가 있다고 생각합니다. int-> string mapping과 함께 enum을 생성하기 위해 swagger를 찾고 있습니다. API는 int를 허용해야합니다. swagger-ui는 덜 중요합니다. 제가 정말로 원하는 것은 다른쪽에 "실제"열거 형 (이 경우 개조를 사용하는 안드로이드 앱)을 사용하여 코드를 생성하는 것입니다.

그래서 내 연구에서 이것은 궁극적으로 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-inactive

감사! 내 프로젝트에서 이것을 사용했지만 .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. 열거 형 변환기 지원을 제외하고이 패키지 없이는 다른 모든 것이 잘 작동하는 것 같습니다.


1
이 규칙을 전역 적으로 설정하는 데 도움이되지만 특정 유형의 열거 형에만 적용해야하는 경우이 문제 를주의 깊게 읽어야합니다 . TL; DR : new StringEnumConverter ()를 속성에만 적용 할 수는 없지만 전체 enum 유형에 적용 할 수 있습니다.
A. Tretiakov

1
우리가 문제에 대해 이야기하고 있다면 완전히 사용자 정의 변환기를 사용하는 것도 불가능하다고 생각합니다. Swagger는 사용자 지정 변환기를 통해 열거 형 값을 실행하지 않습니다. 단순히 StringEnumConverter특별한 경우로 인식 됩니다.
Roman Starkov

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

4
훌륭한 솔루션이지만 DescribeEnumParameters내 프로젝트 에서는의 확장 이 비어 있습니다. 나는 캐스팅했다 paramNonBodyParameter거기에 열거을 확인하십시오if (param is NonBodyParameter nbParam && nbParam.Enum?.Any() == true) { param.Description += DescribeEnum(nbParam.Enum); }
Rabban

내 프로젝트에서 Extensions도 비어 있으며 @Rabban 솔루션을 사용했습니다.
Carlos Beppler 19 년

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, 나는 그것을보고하지 않았지만 나는 있다고 가정합니다. 우리가 그것을 찾아서 나중에 업데이트 할 수 있도록이 게시물에 추가하면 좋습니다.
Bashir Momen


10

.NET CORE 3.1 및 SWAGGER 5

열거 형 을 선택적 으로 문자열로 전달 하는 간단한 솔루션이 필요한 경우 :

using System.Text.Json.Serialization;


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

참고로, 우리 System.Text.Json.SerializationNewtonsoft.Json!


이것은 적절한 값을 표시하고 값을 다시 열거 형으로 변환 할 때도 작동합니다. NuGet 패키지를 추가해야합니다 System.Text.Json.
MovGP0

그게 제가 찾던 것입니다! 단일 열거 형에 문자열을 사용해야하므로 DescribeAllEnumsAsStrings모든 열거 형을 문자열로 변환합니다.
Nilay

9

누구든지 관심이 있다면 코드를 수정하여 작업했습니다.

.NET CORE 3Swagger 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
이것은 매개 변수 유형이 정확히 열거 형일 때만 작동합니다. nullable 열거 형이 아닌 열거 형, 열거 형 컬렉션 등이 아닙니다. 이러한 경우에 대한 내 대답을 확인하십시오.
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)으로 가져 와서 실패한다는 것입니다. 열거 형에 유효한 값이 아니므로 잘못된 요청입니다.
Matyas

3

값이있는 enum stings에 대한 내 변형 :

여기에 이미지 설명 입력

서비스 구성 :

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

필터:

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

2

Startup.cs 내부에 코드 작성

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

2
이 옵션은 Swashbuckle에서 더 이상 사용되지 않습니다. ASP.NET Core 옵션을 사용하는 것이 좋습니다. 그러면 Swashbuckle이이를 반영 할 수 있습니다.
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 '1910.17

1

nullable 열거 형 및 열거 형 컬렉션과 함께 작동하도록 Hosam Rehani의 답변을 수정했습니다. 이전 답변은 속성이 유형과 똑같이 이름이 지정된 경우에만 작동합니다. 이러한 모든 문제는 아래 코드에서 해결됩니다.

.net core 3.x 및 swagger 5.x에서 작동합니다.

어떤 경우에는 열거 형 유형을 두 번 검색하지 않는 것이 더 효율적일 수 있습니다.

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

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

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

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

        enumType = null;
        return false;
    }

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

        return null;
    }

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

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

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

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

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

필터 추가 사용 c.DocumentFilter<SwaggerAddEnumDescriptions>();에 자신감 구성에를 Startup.cs.


0

ASP NET 솔루션

내 API 문서에서 속성이으로 표시되어 있음에도 불구하고 하나의 열거 형이 여전히 int로 표시되었습니다 StringEnumConverter. 위에서 언급 한 모든 열거 형에 전역 설정을 사용할 여유가 없었습니다. SwaggerConfig에 다음 줄을 추가하면 문제가 해결되었습니다.

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

0

우리가 찾던 것에 대한 다른 답변에서 많은 단점이 있었기 때문에 나는 이것에 대해 나 자신의 견해를 제공 할 것이라고 생각했습니다. 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를 사용하여 Swashbuckle에서 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의의 REPO를 이름 지정 방식도 ASP.NET 코어에 활용 될 수 있도록). 다음을 사용하여 ConfigureServices 내의 Startup.cs에서 구성합니다.

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

마지막으로 Swashbuckle에 ISchemaFilter를 등록해야하므로 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 생성기 지원 x-enum-varnames

다른 생성기는 이러한 확장 중 하나를 지원하거나 자체를 가질 수 있습니다.

생성하려면 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.