เอกสาร Swagger UI Web Api นำเสนอ enums เป็นสตริงหรือไม่


118

มีวิธีแสดง enums ทั้งหมดเป็นค่าสตริงในรูปแบบ swagger แทนค่า int หรือไม่?

ฉันต้องการส่งการกระทำ POST และใส่ enums ตามค่าสตริงโดยไม่ต้องดู enum ทุกครั้ง

ฉันลองแล้วDescribeAllEnumsAsStringsแต่เซิร์ฟเวอร์ได้รับสตริงแทนค่า enum ซึ่งไม่ใช่สิ่งที่เรากำลังมองหา

มีใครแก้ปัญหานี้ได้บ้าง?

แก้ไข:

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 รองรับประเภท enum ที่มีทั้งสตริงและค่าจำนวนเต็ม
Hux

1
พฤติกรรมที่คาดหวังของคุณไม่ชัดเจนคุณสามารถอธิบายสิ่งที่คุณต้องการให้ Swagger UI แสดงได้ดีขึ้นและสิ่งที่คุณต้องการ POST / PUT ไปยัง Web API ของคุณพร้อมตัวอย่างหรือไม่?
Federico Dipuma

ยิ่งไปกว่านั้นถ้าฉันมีเมธอด GET ที่ใช้ enum ใน url ฉันต้องการให้โครงร่างอธิบายเป็นสตริงในรายการแบบหล่นลงของค่าที่แนะนำ

เหตุใดการตรวจสอบจำนวนเต็มจึงล้มเหลว ประเภทควรเป็น enum ในโมเดลและตัวจัดรูปแบบสื่อ json จะจัดการสตริงหรือ int ได้อย่างถูกต้อง หากคุณอัปเดตคำถามด้วยตัวอย่างจะช่วยให้เราเข้าใจว่าเหตุใดการตรวจสอบจึงล้มเหลว
Hux

5
หากเป็นแฟล็ก enum ค่านั้นจะต้องเป็นตัวเลขเว้นแต่คุณจะมีค่า enum ที่กำหนดไว้สำหรับทุกชุดค่าผสมที่เป็นไปได้ของแฟล็ก เป็นถั่วที่ผยองไม่แสดงทั้งชื่อและค่าสำหรับแต่ละ enum และแทนที่จะแสดงตัวเลขเพียงอย่างเดียว (ไร้ประโยชน์) หรือชื่อเพียงอย่างเดียว (อีกครั้งไม่มีประโยชน์สำหรับแฟล็กที่ต้องระบุเป็นตัวเลข)
Triynko

คำตอบ:


189

จากเอกสาร :

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

6
สิ่งนี้ใช้ไม่ได้สำหรับฉัน [EnumDataType (typeof (Priority))] [JsonConverter (typeof (StringEnumConverter))]
Lineker

@NH. ใช่ฉันใช้ newtonsoft.json
Lineker

@Lineker โพสต์ข้อผิดพลาดของคุณเป็นคำถามใหม่โดยทำตามคำแนะนำนี้: stackoverflow.com/help/mcve
NH

6
DescribeAllEnumsAsStringsทำงานสำหรับคุณสมบัติของวัตถุและแม้แต่พารามิเตอร์การสืบค้นในการดำเนินการของคอนโทรลเลอร์ อย่างไรก็ตามการใช้งานEnumDataTypeAttributeและJsonConverter(typeof(StringEnumConverter))ไม่ได้ผลสำหรับฉัน
bugged87

2
โซลูชันนี้ละเว้นขั้นตอนสำคัญของการลงทะเบียน StringEnumConverter เป็นตัวแปลงในส่วน AddNewtonsoftJson ของ AddMvc ดูตัวอย่างในคำตอบของ @Roman Starkov ด้านล่าง
A. Tretiakov

123

สำหรับ ASP.NET Core 3 ที่มีไลบรารี Microsoft JSON (System.Text.Json)

ใน Startup.cs / ConfigureServices ():

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

สำหรับ ASP.NET Core 3 ที่มีไลบรารี Json.NET (Newtonsoft.Json)

ติดตั้ง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()));

Pre-ASP.NET Core

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

4
ปัญหาในการใช้ตัวเลือก SerializerSettings.Converters.Add (ใหม่ StringEnumConverter ())) คือการที่คุณเปลี่ยน json สำหรับวิธีการทั้งหมดของคุณไม่ใช่เฉพาะสำหรับ Sawshbuckle
Guillaume

ใครมีวิธีแก้ปัญหาสำหรับ Azure Functions v2 และ / หรือ v3 บ้าง?
Dan Friedman

@DanFriedman พิจารณา Swashbuckle ไม่ทำงานกับ Azure Functions เลยคุณโชคไม่ดี
Ian Kemp

@IanKemp มีการสนับสนุนของบุคคลที่สามกับAzureExtensions.Swashbuckleแพ็คเกจ แต่เหมือน @DanFriedman ฉันไม่สามารถทำให้ enum-to-string ทำงานได้ตามที่คาดไว้
wolfyuk

หากคุณกำลังกำหนดค่าสำหรับ ASP.NET หลัก 3 Newtonsoft ที่วิธีขยายสามารถใช้ได้จากแพคเกจAddSwaggerGenNewtonsoftSupport() NuGet Swashbuckle.AspNetCore.Newtonsoftอ่านเพิ่มเติมที่นี่: github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/…
Andy Vaal

41

ดังนั้นฉันคิดว่าฉันมีปัญหาที่คล้ายกัน ฉันกำลังมองหา swagger เพื่อสร้าง enums พร้อมกับ int -> string mapping API ต้องยอมรับ int ความผยองมีความสำคัญน้อยกว่าสิ่งที่ฉันต้องการจริงๆคือการสร้างรหัสด้วย enum "จริง" ในอีกด้านหนึ่ง (แอป Android ที่ใช้ชุดติดตั้งเพิ่มเติมในกรณีนี้)

ดังนั้นจากการวิจัยของฉันในที่สุดสิ่งนี้ดูเหมือนจะ จำกัด ข้อกำหนด OpenAPI ที่ Swagger ใช้ ไม่สามารถระบุชื่อและหมายเลขสำหรับ enums ได้

ปัญหาที่ดีที่สุดที่ฉันพบเพื่อติดตามคือhttps://github.com/OAI/OpenAPI-Specification/issues/681ซึ่งดูเหมือนว่า "อาจจะเร็ว ๆ นี้" แต่จากนั้น Swagger จะต้องได้รับการอัปเดตและในกรณีของฉัน Swashbuckle เป็น ดี.

สำหรับตอนนี้วิธีแก้ปัญหาของฉันคือการใช้ตัวกรองเอกสารที่ค้นหา enums และเติมคำอธิบายที่เกี่ยวข้องพร้อมกับเนื้อหาของ 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());
    }

}

สิ่งนี้ส่งผลให้เกิดสิ่งต่อไปนี้ใน swagger-ui ของคุณอย่างน้อยคุณก็สามารถ "เห็นสิ่งที่คุณกำลังทำอยู่": ป้อนคำอธิบายภาพที่นี่


1
+1 ฉันต้องการเพิ่มคำอธิบายให้กับ enums (เพื่อ 'อธิบาย enum') ไม่เคยคิดเรื่องนี้ ฉันมีตัวกรองอื่น ๆ อยู่แล้ว แต่กำลังมองหาสิ่งที่เป็น 'อินทรีย์' มากกว่า แต่ไม่มีการสนับสนุน ถ้าอย่างนั้นกรองทุกทาง :)
NSGaga ส่วนใหญ่ไม่ใช้งาน

ขอบคุณ! ฉันใช้สิ่งนี้ในโครงการของฉัน แต่แก้ไขให้ทำงานกับ. NET Core ฉันเพิ่มการใช้งานของฉันเป็นคำตอบ
Gabriel Luci

30

ASP.NET Core 3.1

ในการสร้าง enums เป็นสตริงโดยใช้ Newtonsoft JSON คุณต้องเพิ่มการสนับสนุน Newtonsoft อย่างชัดเจนโดยเพิ่มAddSwaggerGenNewtonsoftSupport()ดังต่อไปนี้:

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


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

Swashbuckle.AspNetCore.Newtonsoftนี้สามารถใช้ได้ผ่านแพคเกจใหม่ ดูเหมือนว่าทุกอย่างจะทำงานได้ดีหากไม่มีแพ็คเกจนี้นอกเหนือจากการรองรับตัวแปลง enum


1
มันจะช่วยให้การติดตั้งการประชุมนี้ทั่วโลก แต่ถ้าคุณต้องการที่จะใช้นี้เฉพาะกับบางประเภทของ enums คุณจะต้องอ่านอย่างนี้ปัญหา TL; DR: ไม่สามารถใช้ StringEnumConverter () ใหม่กับคุณสมบัติเท่านั้น แต่คุณสามารถใช้กับประเภท enum ทั้งหมดได้
A. Tretiakov

1
ฉันคิดว่าถ้าเรากำลังพูดถึง gotchas ก็ไม่สามารถใช้ตัวแปลงที่กำหนดเองได้ทั้งหมด Swagger ไม่เรียกใช้ค่า enum ผ่านตัวแปลงที่กำหนดเอง เพียงแค่รับรู้StringEnumConverterว่าเป็นกรณีพิเศษ
Roman Starkov

22

ฉันต้องการใช้คำตอบของ rory_za ในแอปพลิเคชัน. NET Core แต่ต้องแก้ไขเล็กน้อยเพื่อให้ใช้งานได้ นี่คือการใช้งานที่ฉันสร้างขึ้นสำหรับ. 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)}";
    }
}

จากนั้นเพิ่มสิ่งนี้ในConfigureServicesวิธีการของคุณใน Startup.cs:

c.DocumentFilter<EnumDocumentFilter>();

เป็นไปได้ที่จะลบ Enum: Array [6] ที่ปรากฏด้านล่าง?
Softlion

4
ทางออกที่ดี แต่ส่วนขยายในDescribeEnumParametersโครงการของฉันว่างเปล่า ผมต้องโยนparamไปNonBodyParameterและตรวจสอบ enum มี:if (param is NonBodyParameter nbParam && nbParam.Enum?.Any() == true) { param.Description += DescribeEnum(nbParam.Enum); }
แรบบอน

ในส่วนขยายโครงการของฉันว่างเปล่าเช่นกันใช้โซลูชัน @Rabban
Carlos Beppler

1
@Rabban ฉันอัปเดตรหัสของฉันเพื่อรวมสิ่งนั้น คุณช่วยยืนยันได้ไหมว่าฉันวางไว้ถูกที่แล้ว ฉันไม่ได้มีปัญหานี้ บางทีเวอร์ชันที่ใหม่กว่าอาจเปลี่ยนแปลงสิ่งต่างๆ
Gabriel Luci

@GabrielLuci ยืนยันและอนุมัติแล้ว;)
Rabban

14

.NET CORE 3.1 และ SWAGGER 5

หากคุณต้องการวิธีง่ายๆในการคัดเลือก enums ผ่านเป็นสตริง:

using System.Text.Json.Serialization;


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

หมายเหตุเราใช้System.Text.Json.Serializationเนมสเปซไม่ใช่Newtonsoft.Json!


งานนี้แสดงค่าที่เหมาะสมและยังใช้งานได้เมื่อแปลงค่ากลับเป็น enum System.Text.Jsonโปรดทราบว่าคุณจะต้องเพิ่มแพคเกจ NuGet
MovGP0

นั่นคือสิ่งที่ฉันกำลังมองหา! เนื่องจากฉันต้องใช้สตริงสำหรับ enum เดียวและDescribeAllEnumsAsStringsจะแปลง enums ทั้งหมดเป็นสตริง
Nilay

ขอบคุณสำหรับวิธีง่ายๆนี้ ฉันใช้. NET Core 3.1 และ Swagger 5.5 ไม่จำเป็นต้องใช้ DescribeAllEnumsAsStrings เพียงตั้งค่า [JsonConverter (typeof (JsonStringEnumConverter))] บน enum EX: System.Text.Json.Serialization; [JsonConverter (typeof (JsonStringEnumConverter))] enum สาธารณะหมวดหมู่ {รถยนต์, เครื่องใช้ไฟฟ้า, เฟอร์นิเจอร์, บ้าน, สัตว์เลี้ยง, เบ็ดเตล็ด}
Mahesh

13

หากใครสนใจฉันได้แก้ไขโค้ดเพื่อใช้งานได้

.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
นี้จะทำงานเฉพาะเมื่อชนิดพารามิเตอร์เป็นว่า enum ... ไม่ enum nullable, คอลเลกชันของ enums ฯลฯ ตรวจสอบคำตอบของฉันสำหรับกรณีดังกล่าว
Matyas

เมื่อฉันเรียกใช้รหัสนี้ฉันพบว่า enumOption เป็นประเภท OpenApiString ใน DescribeEnum
Kirsten Greed

1
โซลูชันของคุณใช้งานได้เฉพาะเมื่อฉันเปลี่ยนGetEnumTypeByNameFirstOfDefaultCondition เป็น.FirstOrDefault(x => x.FullName == enumTypeName || x.Name == enumTypeName);
thisрославВиталиевич

12

ด้วย 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()));

แต่ดูเหมือนว่า Swashbuckle Version 5.0.0-rc4 จะไม่พร้อมรองรับสิ่งนั้น ดังนั้นเราจึงต้องใช้ตัวเลือก (เลิกใช้แล้ว) ในไฟล์กำหนดค่า Swashbuckle จนกว่าจะรองรับและสะท้อนให้เห็นเหมือนไลบรารี Newtonsoft

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

ความแตกต่างระหว่างคำตอบนี้กับคำตอบอื่น ๆ คือการใช้ไลบรารี Microsoft JSON แทน Newtonsoft


เฮ้ @Bashir มีปัญหา swachbuckle เพื่อติดตามการขาดการสนับสนุนหรือไม่?
Bernard Vander Beken

สวัสดี @ bernard-vander-beken ฉันไม่ได้รายงาน แต่ฉันคิดว่ามี จะเป็นการดีหากเราสามารถค้นหาได้และเพิ่มในโพสต์นี้เพื่อปรับปรุงในภายหลัง
Bashir Momen

2
ดูเหมือนที่นี่: github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1269
jeremyh

6

ตัวแปรของฉันสำหรับ 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}")));
            }
        }
    }

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 เป็นต้น) ของค่า enum API จะได้รับคำอธิบายแบบเต็มเป็นค่า (เช่น LogicError = 3) ซึ่งจะล้มเหลวในฐานะ a คำขอที่ไม่ถูกต้องเนื่องจากไม่ใช่ค่าที่ถูกต้องสำหรับ enum
Matyas

3

ฉันได้แก้ไขคำตอบของ Hosam Rehani ให้ทำงานกับ enums ที่เป็นโมฆะและคอลเลกชันของ enums ด้วย คำตอบก่อนหน้านี้ยังใช้งานได้ก็ต่อเมื่อมีการตั้งชื่อคุณสมบัติให้เหมือนกับประเภท ปัญหาทั้งหมดนี้ได้รับการแก้ไขในรหัสด้านล่าง

มันทำงานร่วมกับ. net core 3.x และ swagger 5.x.

อาจมีประสิทธิภาพมากขึ้นโดยไม่ค้นหาประเภท enum สองครั้งในบางกรณี

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


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

2

สิ่งนี้ไม่สามารถทำได้กับ OpenAPI มาตรฐาน Enums อธิบายด้วยค่าสตริงเท่านั้น

โชคดีที่คุณสามารถทำได้ด้วยส่วนขยายที่ไม่ได้มาตรฐานบางอย่างที่ใช้โดยโปรแกรมสร้างไคลเอนต์ของคุณ

NSwag รองรับ x-enumNames

AutoRest x-ms-enumสนับสนุน

รองรับ Openapi-generator x-enum-varnames

เครื่องกำเนิดไฟฟ้าอื่น ๆ อาจรองรับหนึ่งในส่วนขยายเหล่านี้หรือมีของตัวเอง

ในการสร้างx-enumNamesสำหรับ NSwag ให้สร้างตัวกรองสคีมาต่อไปนี้:

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

2

หากคุณใช้ newtonsof.json ให้ใช้สิ่งนี้

using Newtonsoft.Json.Converters;


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

หากคุณกำลังใช้ System.Text.Json.Serialization

using System.Text.Json.Serialization;


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

1

.Net Core 3.0

   using Newtonsoft.Json.Converters;

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

1
ใช้ Newtonsoft แทนการทำให้อนุกรม JSON หลักของ asp.net ใหม่
Bashir Momen

1

หากเวอร์ชันของผยองคือ 5.5.x คุณต้อง:

  1. ติดตั้ง: Install-Package Swashbuckle.AspNetCore.Newtonsoft -Version 5.5.0

  2. services.AddSwaggerGenNewtonsoftSupport ();

อ้างอิง: https://github.com/domaindrivendev/Swashbuckle.AspNetCore#systemtextjson-stj-vs-newtonsoft


สิ่งนี้ได้ผลสำหรับฉัน หากคุณใช้ Newtonsoft Json ในโปรเจ็กต์หลักของ asp.net ที่คุณต้องชัดเจนนี้ ขอบคุณ @ user30844147
fingers10

0

ASP NET SOLUTION

ในเอกสาร API ของฉันหนึ่ง enum ยังคงแสดงให้เห็นว่าแม้จะมี int StringEnumConverterทรัพย์สินที่ถูกทำเครื่องหมายด้วย เราไม่สามารถใช้การตั้งค่าส่วนกลางสำหรับ enums ทั้งหมดที่กล่าวมาข้างต้น การเพิ่มบรรทัดนี้ใน SwaggerConfig ช่วยแก้ปัญหา:

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

0

มีข้อบกพร่องหลายประการที่ฉันพบในคำตอบอื่น ๆ สำหรับสิ่งที่เรากำลังมองหาดังนั้นฉันจึงคิดว่าฉันจะจัดหาสิ่งนี้เอง เรากำลังใช้ ASP.NET Core 3.1 กับ System.Text.Json แต่วิธีการของเราใช้งานได้โดยไม่คำนึงถึง JSON serializer ที่ใช้

เป้าหมายของเราคือยอมรับค่าสตริง enum ที่มีอูฐต่ำกว่าทั้งใน ASP.NET Core API และเอกสารเดียวกันใน Swagger ขณะนี้เรากำลังใช้ประโยชน์[DataContract]และ[EnumMember]ดังนั้นแนวทางคือการใช้ค่าต่ำกว่าตัวอักษรอูฐจากคุณสมบัติมูลค่า EnumMember และใช้ทั่วทั้งกระดาน

enum ตัวอย่างของเรา:

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

เราจะใช้ค่า EnumMember ใน Swashbuckle โดยใช้ ISchemaFilter ดังต่อไปนี้:

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 Core ด้วย กำหนดค่าใน Startup.cs ภายใน ConfigureServices ด้วย:

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)จะ จำกัด เฉพาะคุณสมบัติ enum ที่ประกาศจริงเช่น "Blue" ฉันยังปรับกรณี "else" เพื่อส่งคืน Member.Name หากไม่มี[EnumMember]แอตทริบิวต์
user2864740
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.