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

时间:2019-07-19 04:06:23

标签: c# asp.net enums model-binding core

我正试图让枚举在描述中(或任何其他属性)以友好的方式显示友好名称。还尝试解析控制器操作中在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之外调用端点,则会返回400错误。 3.我可以在操作[FromBody]参数中成功使用0,1或ASCENDENING,DESCENDING值。但是,这不是预期的。我将要接收asc,desc,并希望能够在主体模型上成功解析它并将其映射到enum属性。在另一方面,当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

2 个答案:

答案 0 :(得分:0)

这是为我做的:

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

I found the it here

答案 1 :(得分:0)

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

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

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

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

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