Реализуйте TypeConverter для описания Enum в WebAPI - PullRequest
1 голос
/ 24 июня 2019

Я использую DescriptionAttribute в Enums для предоставления описания, которое включает пробелы. Я создал несколько методов расширения, которые будут возвращать строковое описание перечисления и / или возвращать значение перечисления из строкового описания.

Теперь я хочу, чтобы мой WebAPI использовал эти методы расширения для обработки преобразования типов Enum вместо TypeConverter по умолчанию, чтобы я мог передать значение типа "Car Wash" и сопоставить его с Enum.

Есть ли способ переопределить строку по умолчанию для Enum TypeConverter?

Окружающая среда .NetCore 2.x

Обновление - мой текущий код

Мой текущий код прекрасно работает, когда контроллер сериализует объект в JSON для отправки клиенту. Учитывая приведенное ниже значение Enum, значение enum 0 приведет к тому, что клиент получит строку «Mental Health» - идеально. Тем не менее, теперь, когда клиент отправляет «Mental Health» обратно на сервер - мне нужно преобразовать обратно в AgencyTpes.MentalHealth. В данный момент механизм привязки выдает ошибку.

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

Мои расширения Enum, работающие с DescriptionAttribute

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 для включения контроллеров для преобразования enum в строку

//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

Вот пример кода объекта Controller & Domain

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 Ответ

2 голосов
/ 27 июня 2019

Вы можете попробовать переопределить значение по умолчанию 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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...