在 Swagger 下拉菜单和 json 上显示枚举成员友好名称

Show Enum member friendly name on Swagger dropdown and json

我正在尝试让枚举在响应时大摇大摆地显示描述(或任何其他属性)中的友好名称。还尝试解析控制器操作中 body/querystring 上设置的友好名称,而不尝试 400 BadRequest 或任何类型的验证错误。我还注意到,我拥有的自定义通用 JsonConverter 也无法正常工作。 ReadJson() 方法根本没有被调用。我怎样才能让它工作?

[JsonConverter(typeof(JsonEnumConverter<SortDirectionType>))]
public enum SortDirectionType
{
    [Description("asc")]
    ASCENDING,
    [Description("desc")]
    DESCENDING
}

我正在尝试让 swagger-ui 将 asc 和 desc 显示为下拉列表中的值,而不是 ASCENDING 和 DESCENDING。这意味着我不能使用 c.DescribeAllEnumsAsStrings()。如果我不使用它,那么下拉列表会显示 0,1,因为它应该代表枚举成员值。现在我可以使用 [EnumMember(Value="asc"] 属性而不是 [Description("asc")] 属性。然而,随后发生了两件事:

  1. 要么 swagger-ui 抛出客户端验证并突出显示周围有红线的字段
  2. 或者如果我尝试在 swagger 之外调用端点 returns 400 错误。
  3. 我能够在操作 [FromBody] 参数中成功使用 0,1 或 ASCENDING、DESCENDING 值。然而,这不是预期的。我将接收 asc、desc,并希望能够在 body 模型上成功解析并将其映射到枚举 属性。另一方面,当 json 呈现时,它应该呈现友好名称。

附加代码:

public class JsonEnumConverter<T> : JsonConverter where T : struct, IComparable, IConvertible, IFormattable
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(T);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var type = typeof(T);

        if (!type.IsEnum) throw new InvalidOperationException();

        var enumDescription = (string)reader.Value;

        return enumDescription.GetEnumValueFromDescription<T>();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var type = typeof(T);

        if (!type.IsEnum) throw new InvalidOperationException();

        if (value != null)
        {
            if (value is Enum sourceEnum)
            {
                writer.WriteValue(sourceEnum.GetDescriptionFromEnumValue());
            }
        }
    }
}

public static class EnumExtensions
{
    public static string GetDescriptionFromEnumValue(this Enum @enum)
    {
        FieldInfo fi = @enum.GetType().GetField(@enum.ToString());

        DescriptionAttribute[] attributes =
            (DescriptionAttribute[])fi.GetCustomAttributes(
            typeof(DescriptionAttribute),
            false);

        if (attributes != null &&
            attributes.Length > 0)
            return attributes[0].Description;
        else
            return @enum.ToString();
    }

    public static T GetEnumValueFromDescription<T>(this string description)
    {
        var type = typeof(T);

        if (!type.IsEnum)
            throw new InvalidOperationException();

        foreach (var field in type.GetFields())
        {
            if (Attribute.GetCustomAttribute(field,
                typeof(DescriptionAttribute)) is DescriptionAttribute attribute)
            {
                if (attribute.Description == description)
                    return (T)field.GetValue(null);
            }
            else
            {
                if (field.Name == description)
                    return (T)field.GetValue(null);
            }
        }

        throw new ArgumentException($"No matching value for enum {nameof(T)} found from {description}.",$"{nameof(description)}"); // or return default(T);
    }
}

https://github.com/domaindrivendev/Swashbuckle/issues/1318

这就是为我做的:

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

I found the it here

我想出了一个办法。它可能不一定是您的解决方案,但是如果您可以让它工作,那么我很高兴能提供帮助。

最终将枚举格式更改为字符串而不是默认下拉列表。这样我就可以将 asc/desc 值发送到 api。 Swagger 接受了这些值并且没有抛出验证错误。我在 .net core api 上编写的转换器也能够很好地转换它们。

c.MapType<SortDirectionType>(() => new Schema { Type = "string", Format = "string" });

除此之外,您可能还想禁用自动启动的 asp.net 核心 2.2 验证的默认行为。不确定他们为什么选择将其设置为默认行为。

services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressModelStateInvalidFilter = true;
});