在WebAPI中实现TypeConverter来描述Enum

时间:2019-06-24 18:24:37

标签: c# asp.net-core-webapi

我在Enums上使用DescriptionAttribute来提供包含空格的描述。我创建了一些扩展方法,这些方法将返回枚举的字符串描述和/或从字符串描述返回枚举值。

现在,我希望我的WebAPI使用这些扩展方法来处理Enum类型转换,而不是默认的TypeConverter,以便我可以传递类似"Car Wash"的值并将其映射到Enum。

是否可以将默认字符串覆盖为Enum TypeConverter?

环境 .NetCore 2.x

更新-我当前的代码

当Controller将对象序列化为JSON以发送到客户端时,我当前的代码非常有用。给定下面的Enum,枚举值0将导致客户端获得字符串“ Mental Health”-完美。但是,现在客户端将“心理健康”发送回服务器时,我需要将其转换回AgencyTpes.MentalHealth。现在,绑定引擎会引发错误。

//Example Enum
public enum AgencyTypes {
   [Description("Mental Health")]
   MentalHealth,
   Corrections,
   [Description("Drug & Alcohol")]
   DrugAndAlcohol,
   Probation
}

DescriptionAttribute一起使用的我的Enum扩展名

public static class EnumExtensions
{
    public static string ToDisplayString(this Enum values)
    {
        var attribute = value.GetType().GetMember(value.ToString())
           .FirstOrDefault()?.GetCustomAttribute<DescriptionAttribute>();
        return attribute ?.Description ?? value.ToString();
     }

     public static object GetValueFromDescription(string description, Type enumType)
     {
         return Convert.ChangeType(LookupDescription(description,enumType),enumType);
     }

     public static T GetValueFromDescription<T>(string description) where T: struct
     {
        return (T)LookupDescription(description, typeof(T));
     }

     private static object LookupDescription(string description, Type enumType)
     {
        if(!enumType.IsEnum)
           throw new ArgumentException("Type provided must be an Enum", enumType.Name);

        foreach(var field in enumType.GetFields())
        {
           var attribute = Attribute.GetCustomAttribute(field, tyepof(DescriptionAttribute)) as DescriptionAttribute;
           if((attribute != null && attribute.Description == description)
               || field.Name == description)
           {
              return field.GetValue(null);
           }
         }
         throw new ArgumentException($"Requested value for '{description}' in enum {enumType.Name} was not found", nameof(description));
     }
}

我的JSON覆盖使控制器能够将枚举转换为字符串

//Startup.cs
services.AddMvc().SetCompatibilityVersion(Compatibility.Version_2_2)
  .AddJsonOptions(options => 
  {
     options.SerializerSettings.Converters.Add(new StringAnnotationEnumConverter());
  });


public class StringAnnotationEnumConverter : StringEnumConverter
{
   public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
   {
      var token = JToken.Load(reader);
      var value = token.ToString();
      if(reader.TokenType == JsonToken.String)
          return EnumExtensions.GetValueFromDescription(value, objectType);
      else
          return base.ReadJson(reader, objectType, existingValue, serializer);
   }

   public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
   {
       if(value == null)
       {
          writer.WriteNull();
          return;
       }

       Enum e = (Enum)value;
       string enumName = e.ToDisplayString();
       if(string.IsNullOrWhiteSpace(enumName))
          throw new JsonSerializationException(String.Format("Integer value {0} is not allowed.",e.ToString("D")));

       writer.WriteValue(enumName);
    }
}

更新2-WebAPI

这是控制器和域对象的示例代码

public class Agency 
{
   public int Id {get; set;}
   public string Name {get; set;}
   public AgencyTypes AgencyType {get; set;}
   ...
 }


 [ApiController]
 public class AgencyController : ControllerBase
 {
    [HttpPost]
    public async Task<IActionResult> Agency([FromForm] Agency agency)
    {
       ...
    }
  }

1 个答案:

答案 0 :(得分:2)

您可以尝试覆盖默认的EnumConverter来进行自定义属性检查

public class MyEnumConverter: EnumConveter {
    public MyEnumConverter(Type type) : base(type) {
    }


    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
        if (value is string) {
            var enumString = (string)value;
            return EnumExtensions.GetValueFromDescription(enumString, EnumType);
        }
        return base.ConvertFrom(context, culture, value);
    }
}

并使用TypeConverter属性装饰枚举

[TypeConverter(typeof(MyEnumConverter))]
public enum AgencyTypes {
    [System.ComponentModel.Description("Mental Health")]
    MentalHealth,
    Corrections,
    [System.ComponentModel.Description("Drug & Alcohol")]
    DrugAndAlcohol,
    Probation
}