是否有一种方法显示所有枚举作为他们的字符串值在swagger而不是他们的int值?

我希望能够提交POST动作,并根据它们的字符串值放置枚举,而不必每次都查看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
}

当前回答

我得到了它的工作。net 6 Web API使用以下代码从其他答案在这里:

1 -创建一个DocumentFilter

/// <summary>
/// Add enum value descriptions to Swagger
/// </summary>
public class SwaggerEnumDocumentFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        // add enum descriptions to result models
        foreach (var property in swaggerDoc.Components.Schemas)
        {
            var propertyEnums = property.Value.Enum;
            if (propertyEnums is { Count: > 0 })
            {
                property.Value.Description += DescribeEnum(propertyEnums, property.Key);
            }
        }

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

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

            var affectedOperations = new List<OperationType> { OperationType.Get, OperationType.Post, OperationType.Put, OperationType.Patch };

            foreach (var operation in pathItem.Operations)
            {
                if (affectedOperations.Contains(operation.Key))
                {
                    DescribeEnumParameters(operation.Value.Parameters);
                }
            }
        }
    }

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

        foreach (var param in parameters)
        {
            if (param.Schema.Reference != null)
            {
                var enumType = GetEnumTypeByName(param.Schema.Reference.Id);
                var names = Enum.GetNames(enumType).ToList();

                param.Description += string.Join(", ", names.Select(name => $"{Convert.ToInt32(Enum.Parse(enumType, name))} - {name}").ToList());
            }
        }
    }

    private static Type GetEnumTypeByName(string enumTypeName)
    {
        if (string.IsNullOrEmpty(enumTypeName))
        {
            return null;
        }

        try
        {
            return AppDomain.CurrentDomain
                            .GetAssemblies()
                            .SelectMany(x => x.GetTypes())
                            .Single(x => x.FullName != null
                                      && x.Name == enumTypeName);
        }
        catch (InvalidOperationException e)
        {
            throw new Exception($"SwaggerDoc: Can not find a unique Enum for specified typeName '{enumTypeName}'. Please provide a more unique enum name.");
        }
    }

    private static string DescribeEnum(IEnumerable<IOpenApiAny> enums, string propertyTypeName)
    {
        var enumType = GetEnumTypeByName(propertyTypeName);

        if (enumType == null)
        {
            return null;
        }

        var parsedEnums = new List<OpenApiInteger>();
        foreach (var @enum in enums)
        {
            if (@enum is OpenApiInteger enumInt)
            {
                parsedEnums.Add(enumInt);
            }
        }

        return string.Join(", ", parsedEnums.Select(x => $"{x.Value} - {Enum.GetName(enumType, x.Value)}"));
    }

}

2 -将其添加到Program.cs文件中

   services.AddSwaggerGen(config =>
        {

            config.DocumentFilter<SwaggerEnumDocumentFilter>();

        })

其他回答

在这里搜索答案后,我发现了在模式中显示枚举的问题的部分解决方案[SomeEnumString = 0, AnotherEnumString = 1],但与此相关的所有答案都只是部分正确的,正如@OhWelp在其中一个评论中提到的那样。

下面是。net core的完整解决方案(2、3,目前在6上工作):

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

                var names = Enum.GetNames(context.Type).ToList();

                names.ForEach(name => model.Enum.Add(new OpenApiString($"{GetEnumIntegerValue(name, context)} = {name}")));


                 // the missing piece that will make sure that the new schema will not replace the mock value with a wrong value 
                // this is the default behavior - the first possible enum value as a default "example" value
                model.Example = new OpenApiInteger(GetEnumIntegerValue(names.First(), context));
            }
        }

        private int GetEnumIntegerValue(string name, SchemaFilterContext context) => Convert.ToInt32(Enum.Parse(context.Type, name));
    }

在启动/程序中:

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

编辑:对代码进行了一些重构,如果你想看到原始版本,它与其余的答案更相似,请检查编辑的年表。

.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!

我刚刚做了这个,它工作得很好!

Startup.cs

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

Model.cs

public enum ColumnType {
  DATE = 0
}

swagger.json

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

我希望这能帮助你,就像它帮助了我一样!

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

我想我也有类似的问题。我正在寻找swagger与int ->字符串映射一起生成枚举。API必须接受整型。swagger-ui不那么重要,我真正想要的是代码生成与另一边的“真实”enum(在这种情况下使用改装的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上产生如下的结果,这样至少你可以“看到你在做什么”: