Tài liệu Swagger UI Web Api Trình bày enums dưới dạng chuỗi?


107

Có cách nào để hiển thị tất cả các enum dưới dạng giá trị chuỗi của chúng ở dạng swagger thay vì giá trị int của chúng không?

Tôi muốn có thể gửi các hành động POST và đặt các enum theo giá trị chuỗi của chúng mà không cần phải nhìn vào enum mỗi lần.

Tôi đã thử DescribeAllEnumsAsStringsnhưng sau đó máy chủ nhận các chuỗi thay vì giá trị enum, đây không phải là thứ chúng tôi đang tìm kiếm.

Có ai đã giải quyết điều này?

Biên tập:

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
Bạn có muốn lược đồ mô tả giá trị dưới dạng một chuỗi nhưng sau đó đăng một số nguyên lên máy chủ không? JSON.net sẽ xử lý tốt cả hai giá trị, vậy phiên bản chỉ số nguyên có phải là một yêu cầu xác định không? Tôi không nghĩ rằng Swagger hỗ trợ một kiểu enum với cả giá trị chuỗi và số nguyên.
Hux

1
Hành vi mong đợi của bạn là không rõ ràng, bạn có thể giải thích rõ hơn những gì bạn muốn Swagger UI hiển thị và những gì bạn muốn ĐĂNG / PUT vào API Web của mình với các ví dụ không?
Federico Dipuma

Hơn nữa, nếu tôi có phương pháp GET mà phải mất enum trong url, tôi muốn chương trình này để mô tả nó như là chuỗi trong danh sách thả các giá trị đề nghị xuống

Tại sao xác thực số nguyên không thành công? Kiểu phải là một enum trong mô hình và trình định dạng phương tiện json sẽ xử lý chính xác một chuỗi hoặc int. Nếu bạn cập nhật câu hỏi bằng một ví dụ, điều đó sẽ giúp chúng tôi hiểu tại sao việc xác thực không thành công.
Hux

4
Nếu đó là một enum cờ, nó phải là số, trừ khi bạn có các giá trị enum được xác định cho mọi tổ hợp cờ có thể có. Thật là điên rồ khi swagger không hiển thị CẢ tên và giá trị cho mỗi enum, và thay vào đó hiển thị một mình số (vô dụng) hoặc một mình tên (một lần nữa, vô dụng đối với các cờ phải được chỉ định là số).
Triynko

Câu trả lời:


188

Từ các tài liệu :

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

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

Ngoài ra, nếu bạn chỉ muốn hành vi này trên một loại và thuộc tính cụ thể, hãy sử dụng StringEnumConverter:

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

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

5
điều này không hiệu quả đối với tôi. [EnumDataType (typeof (Priority))] [JsonConverter (typeof (StringEnumConverter))]
Lineker,

@NH. vâng, tôi đã sử dụng newtonsoft.json
Lineker

@Lineker, hãy đăng lỗi của bạn dưới dạng câu hỏi mới, làm theo hướng dẫn sau: stackoverflow.com/help/mcve
NH.

Cám ơn! Tôi nghĩ tôi cũng có thể để lại nhận xét của bạn trong nguồn #thiswilldothetrick
Simon_Weaver

5
DescribeAllEnumsAsStringsđã làm việc cho các thuộc tính đối tượng và thậm chí các tham số truy vấn trên các hành động của bộ điều khiển. Tuy nhiên, sử dụng EnumDataTypeAttributeJsonConverter(typeof(StringEnumConverter))không làm việc cho tôi.
bugged87

88

Đối với ASP.NET Core 3 với thư viện JSON của Microsoft (System.Text.Json)

Trong Startup.cs / ConfigureServices ():

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

Đối với ASP.NET Core 3 với thư viện Json.NET (Newtonsoft.Json)

Cài đặt Swashbuckle.AspNetCore.Newtonsoftgói.

Trong Startup.cs / ConfigureServices ():

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

Đối với ASP.NET Core 2

Trong Startup.cs / ConfigureServices ():

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

Pre-ASP.NET Core

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

4
Vấn đề khi sử dụng options.SerializerSettings.Converters.Add (new StringEnumConverter ())) là việc bạn thay đổi json cho tất cả các phương thức của mình, không chỉ cho Sawshbuckle.
Guillaume

Có ai có giải pháp cho Azure Functions v2 và / hoặc v3 không?
Dan Friedman

@DanFriedman Xem xét Swashbuckle hoàn toàn không hoạt động với Azure Functions, bạn đã không gặp may.
Ian Kemp

@IanKemp Có hỗ trợ của bên thứ ba với AzureExtensions.Swashbucklegói nhưng giống như @DanFriedman, tôi không thể làm cho enum-to-string hoạt động như mong đợi
wolfyuk

40

Vì vậy, tôi nghĩ rằng tôi có một vấn đề tương tự. Tôi đang tìm kiếm swagger để tạo enums cùng với ánh xạ chuỗi int ->. API phải chấp nhận int. Vấn đề thấp hơn là swagger-ui, những gì tôi thực sự muốn là tạo mã với một enum "thực" ở phía bên kia (các ứng dụng android sử dụng trang bị thêm trong trường hợp này).

Vì vậy, từ nghiên cứu của tôi, đây dường như là một giới hạn của đặc tả OpenAPI mà Swagger sử dụng. Không thể chỉ định tên và số cho enums.

Vấn đề tốt nhất mà tôi tìm thấy để theo dõi là https://github.com/OAI/OpenAPI-Specification/issues/681 trông giống như một "có thể sớm" nhưng sau đó Swagger sẽ phải được cập nhật và trong trường hợp của tôi, Swashbuckle là tốt.

Hiện tại, cách giải quyết của tôi là triển khai bộ lọc tài liệu tìm kiếm enum và điền mô tả có liên quan với nội dung của 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());
    }

}

Điều này dẫn đến một cái gì đó giống như sau trên swagger-ui của bạn, vì vậy ít nhất bạn có thể "biết những gì bạn đang làm": nhập mô tả hình ảnh ở đây


1
+1 Tôi đang tìm cách thêm mô tả vào enum (chỉ để 'mô tả enum'), chưa bao giờ nghĩ đến điều này. Tôi đã có sẵn các bộ lọc khác nhưng đang tìm kiếm thứ gì đó 'hữu cơ' hơn, nhưng không có hỗ trợ. Vậy thì, lọc tất cả các cách :)
NSGaga-chủ yếu là-không hoạt động

Cảm ơn! Tôi đã sử dụng cái này trong dự án của mình, nhưng đã sửa đổi nó để hoạt động với .NET Core. Tôi đã thêm phần triển khai của mình làm câu trả lời.
Gabriel Luci,

27

ASP.NET Core 3.1

Để tạo enums dưới dạng chuỗi sử dụng Newtonsoft JSON, bạn phải thêm hỗ trợ Newtonsoft một cách rõ ràng bằng cách thêm AddSwaggerGenNewtonsoftSupport()như sau:

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


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

Điều này có sẵn thông qua một gói mới , Swashbuckle.AspNetCore.Newtonsoft. Có vẻ như mọi thứ khác hoạt động tốt mà không có gói này ngoài hỗ trợ trình chuyển đổi enum.


1
Nó giúp thiết lập quy ước này trên toàn cầu, nhưng nếu bạn chỉ cần áp dụng điều này cho một số loại enum nhất định, bạn sẽ cần phải đọc kỹ vấn đề này . TL; DR: Không thể chỉ áp dụng StringEnumConverter () mới cho thuộc tính, nhưng bạn có thể áp dụng nó cho toàn bộ kiểu enum.
A. Tretiakov

1
Tôi cho rằng nếu chúng ta đang nói về gotchas, thì cũng không thể sử dụng một công cụ chuyển đổi hoàn toàn tùy chỉnh. Swagger không chạy các giá trị enum thông qua trình chuyển đổi tùy chỉnh; nó chỉ đơn giản nhận ra StringEnumConverterlà một trường hợp đặc biệt.
Roman Starkov

22

Tôi muốn sử dụng câu trả lời của rory_za trong ứng dụng .NET Core, nhưng tôi phải sửa đổi nó một chút để nó hoạt động. Đây là cách triển khai tôi đã nghĩ ra cho .NET Core.

Tôi cũng đã thay đổi nó để nó không giả định là kiểu cơ bản intvà sử dụng các dòng mới giữa các giá trị để dễ đọc hơn.

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

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

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

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

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

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

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

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

Sau đó, thêm nó vào ConfigureServicesphương thức của bạn trong Startup.cs:

c.DocumentFilter<EnumDocumentFilter>();

Có thể xóa Enum: Array [6] xuất hiện bên dưới không?
Softlion

4
Giải pháp tuyệt vời, nhưng phần mở rộng trong DescribeEnumParametersdự án của tôi trống. Tôi phải chuyển paramđến NonBodyParametervà kiểm tra enum ở đó:if (param is NonBodyParameter nbParam && nbParam.Enum?.Any() == true) { param.Description += DescribeEnum(nbParam.Enum); }
Rabban

Trong dự án của tôi, Tiện ích mở rộng cũng trống, đã sử dụng giải pháp @Rabban.
Carlos Beppler

1
@Rabban Tôi đã cập nhật mã của mình để bao gồm điều đó. Bạn có thể chỉ cần xác minh tôi đặt nó vào đúng nơi không? Tôi không có vấn đề này. Có lẽ một phiên bản mới hơn đã thay đổi mọi thứ.
Gabriel Luci

@GabrielLuci Đã xác nhận và phê duyệt;)
Rabban

12

Với 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()));

Nhưng có vẻ như Swashbuckle Version 5.0.0-rc4 chưa sẵn sàng hỗ trợ điều đó. Vì vậy, chúng ta cần sử dụng một tùy chọn (không được dùng nữa) trong tệp cấu hình Swashbuckle cho đến khi nó hỗ trợ và phản ánh nó giống như thư viện Newtonsoft.

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

Sự khác biệt giữa câu trả lời này và các câu trả lời khác là chỉ sử dụng thư viện JSON của Microsoft thay vì Newtonsoft.


Xin chào @Bashir, có vấn đề gì khó khăn để theo dõi việc thiếu hỗ trợ đó không?
Bernard Vander Beken

Xin chào @ bernard-vander-beken, tôi không báo cáo điều đó nhưng tôi cho rằng có. Thật tốt nếu chúng ta có thể tìm thấy nó và thêm nó vào bài đăng này để cập nhật sau.
Bashir Momen


10

.NET CORE 3.1 và SWAGGER 5

nếu bạn cần một giải pháp đơn giản để tạo chọn lọc các enum được chuyển dưới dạng chuỗi:

using System.Text.Json.Serialization;


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

Lưu ý, chúng tôi sử dụng System.Text.Json.Serializationkhông gian tên, không sử dụng Newtonsoft.Json!


Cái này hoạt động hiển thị các giá trị thích hợp và cũng hoạt động khi chuyển đổi các giá trị trở lại enum. Lưu ý rằng bạn cần thêm gói NuGet System.Text.Json.
MovGP0

Đó là những gì tôi đang tìm kiếm! Vì tôi phải sử dụng chuỗi chỉ cho một enum duy nhất và DescribeAllEnumsAsStringssẽ chuyển đổi tất cả các enum thành chuỗi.
Nilay

9

nếu có ai quan tâm, tôi đã sửa đổi mã để làm việc với

.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
Điều này chỉ hoạt động khi kiểu tham số chính xác là enum ... không phải enum nullable, tập hợp các enum, v.v. Kiểm tra câu trả lời của tôi cho những trường hợp đó.
Matyas

4

Tôi vừa làm điều này và nó hoạt động tốt!

Startup.cs

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

Model.cs

public enum ColumnType {
  DATE = 0
}

swagger.json

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

Tôi hy vọng điều này sẽ giúp bạn làm thế nào nó đã giúp tôi!


2
DescribeAllEnumsAsStringskhông được dùng nữa
Node.JS

4

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

}

và trong Startup.cs:

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

Kết quả


4
Mặt trái của điều này là khi thực hiện một yêu cầu, thay vì chỉ truyền đại diện int (ví dụ như 2) của một giá trị enum, API sẽ nhận mô tả đầy đủ dưới dạng một giá trị (như LogicError = 3), điều này sẽ không thành công yêu cầu không hợp lệ vì nó không phải là giá trị hợp lệ cho enum.
Matyas

3

Biến thể của tôi cho enum stings với các giá trị:

nhập mô tả hình ảnh ở đây

Định cấu hình dịch vụ:

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

Bộ lọc:

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

viết mã bên trong Startup.cs

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

2
Tùy chọn này không được chấp nhận trong Swashbuckle. Bạn nên sử dụng tùy chọn ASP.NET Core và sau đó Swashbuckle có thể phản ánh điều đó.
Bashir Momen

2

Tôi đã tìm thấy giải pháp tốt Ở đây:

@PauloVetor - đã giải quyết nó bằng ShemaFilter như thế này:

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

Và trong Startup.cs:

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

Bạn cũng nên đảm bảo rằng bạn cập nhật model.Formatlên "string"như thường lệ "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
Nó đang sử dụng Newtonsoft thay vì tuần tự hóa JSON lõi asp.net mới.
Bashir Momen

1

Tôi đã sửa đổi câu trả lời của Hosam Rehani để làm việc với các enum vô hiệu và với cả bộ sưu tập các enum. Câu trả lời trước cũng chỉ hoạt động nếu một thuộc tính được đặt tên chính xác như kiểu của nó. Tất cả những vấn đề này được giải quyết trong đoạn mã dưới đây.

Nó hoạt động với .net core 3.x và swagger 5.x.

nó có thể hiệu quả hơn bằng cách không tìm kiếm kiểu enum hai lần trong một số trường hợp.

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

để sử dụng bộ lọc thêm c.DocumentFilter<SwaggerAddEnumDescriptions>();vào cấu hình swagger trong Startup.cs.


0

GIẢI PHÁP MẠNG ASP

Trong tài liệu api của tôi, một enum vẫn được hiển thị là int mặc dù thuộc tính được đánh dấu bằng StringEnumConverter. Chúng tôi không đủ khả năng sử dụng cài đặt toàn cầu cho tất cả các môi trường được đề cập ở trên. Thêm dòng này vào SwaggerConfig đã giải quyết được vấn đề:

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

0

Có một số thiếu sót mà tôi tìm thấy trong các câu trả lời khác cho những gì chúng tôi đang tìm kiếm, vì vậy tôi nghĩ rằng tôi sẽ cung cấp phương án của riêng mình cho vấn đề này. Chúng tôi đang sử dụng ASP.NET Core 3.1 với System.Text.Json, nhưng cách tiếp cận của chúng tôi hoạt động bất kể bộ tuần tự JSON được sử dụng.

Mục tiêu của chúng tôi là chấp nhận các giá trị chuỗi enum dựa trên lạc đà thấp hơn trong cả API ASP.NET Core cũng như lập tài liệu giống nhau trong Swagger. Chúng tôi hiện đang sử dụng [DataContract][EnumMember] , vì vậy, cách tiếp cận là lấy giá trị dựa trên lạc đà thấp hơn từ thuộc tính giá trị EnumMember và sử dụng giá trị đó trên diện rộng.

Enum mẫu của chúng tôi:

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

Chúng tôi sẽ sử dụng các giá trị EnumMember trong Swashbuckle bằng cách sử dụng ISchemaFilter như sau:

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

Chúng tôi đang sử dụng gói NuGet của bên thứ ba (GitHub repo ) để đảm bảo rằng lược đồ đặt tên này cũng được sử dụng trong ASP.NET Core. Định cấu hình nó trong Startup.cs trong ConfigureServices với:

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

Cuối cùng, chúng ta cần đăng ký ISchemaFilter của mình trong Swashbuckle, vì vậy cũng thêm phần sau vào ConfigureServices ():

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

GetMembers()sẽ tốt hơn nếu GetMembers(BindingFlags.Static | BindingFlags.Public)chỉ giới hạn các thuộc tính enum được khai báo thực tế, chẳng hạn như "Blue". Tôi cũng điều chỉnh trường hợp "khác" để trả về Tên thành viên nếu không có [EnumMember]thuộc tính.
user2864740

0

Điều này là không thể với OpenAPI tiêu chuẩn. Enums chỉ được mô tả với các giá trị chuỗi của chúng.

May mắn thay, bạn có thể làm điều đó với một số tiện ích mở rộng không chuẩn được sử dụng bởi trình tạo khách hàng của bạn.

NSwag hỗ trợ x-enumNames

Hỗ trợ AutoRest x-ms-enum.

Hỗ trợ máy phát điện Openapi x-enum-varnames

Các trình tạo khác có thể hỗ trợ một trong những phần mở rộng này hoặc có phần mở rộng của riêng họ.

Để tạo x-enumNamescho NSwag, hãy tạo bộ lọc lược đồ sau:

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

Và đăng ký nó là:

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.