PavanKumar GVVS
PavanKumar GVVS

Reputation: 1045

How to ignore case sensitive for Enum Data Type in Data Annotations in .NET

I am working on REST API. I have JSON input in POST request contains many parameters of which one is user language.

JSON:

{
    "userlanguage":"en"
}

I have created Enum class for all Languages.

Note: For reference I provided English, Hindi languages only.

public enum Language
{
    EN = 0,
    HI =1
}

To validate Class, I am using EnumDataType and Required data annotations.

public class UserDetails
{
    [Required]
    [EnumDataType(typeof(Language), ErrorMessage = "Invalid Language Supported.")]
    [JsonProperty("userlanguage")]
    public string? UserLanguage { get; set; }
}

I created Extension class to validate any class models.

public static class HttpRequestValidationExtension
{
    public static bool IsValid(this object o, out ICollection<ValidationResult> validationResults)
    {
        validationResults = new List<ValidationResult>();
        return Validator.TryValidateObject(o, new ValidationContext(o, null, null), validationResults, true);
    }
}

Usage in Controller Class:

UserDetails userDetails= JsonConvert.DeserializeObject<UserDetails>(requestBody);

if (!userDetails.IsValid(validationResults: out var validationResults))
{
    string errorMessage = "Bad Request.";
    int statusCode = 400;
    return DisplayErrorMessage
        (statusCode, 
        string.Join("", validationResults.Select(s => s.ErrorMessage).FirstOrDefault()),
        functionName, 
        string.Join("", validationResults.Select(s => s.MemberNames).FirstOrDefault()));
}

Problem: If I supply EN my validation is SUCCESS. If I supply en my validation is FIALED. Is there any way to ignore case?

Upvotes: 2

Views: 1307

Answers (1)

MichaelMao
MichaelMao

Reputation: 2796

After checked the source code of EnumDataType I think you could implement a custom EnumDataType to archive what you want.

So I change the EnumDataType to EnumIgnoreCaseDataTypeAttribute

 public class UserDetails
 {
     [Required]
     [EnumIgnoreCaseDataTypeAttribute(typeof(Language), ErrorMessage = "Invalid Language Supported.")]
     [JsonProperty("userlanguage")]
     public string? UserLanguage { get; set; }
 }

 [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = false)]
 public class EnumIgnoreCaseDataTypeAttribute : DataTypeAttribute
 {
     public Type EnumType { get; private set; }

     public EnumIgnoreCaseDataTypeAttribute(Type enumType)
         : base("Enumeration")
     {
         this.EnumType = enumType;
     }

     public override bool IsValid(object value)
     {
         if (this.EnumType == null)
         {
             throw new InvalidOperationException();
         }
         if (!this.EnumType.IsEnum)
         {
             throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "", this.EnumType.FullName));
         }

         if (value == null)
         {
             return true;
         }
         string stringValue = value as string;
         if (stringValue != null && String.IsNullOrEmpty(stringValue))
         {
             return true;
         }

         Type valueType = value.GetType();
         if (valueType.IsEnum && this.EnumType != valueType)
         {
             // don't match a different enum that might map to the same underlying integer
             // 
             return false;
         }

         if (!valueType.IsValueType && valueType != typeof(string))
         {
             // non-value types cannot be converted
             return false;
         }

         if (valueType == typeof(bool) ||
             valueType == typeof(float) ||
             valueType == typeof(double) ||
             valueType == typeof(decimal) ||
             valueType == typeof(char))
         {
             // non-integral types cannot be converted
             return false;
         }

         object convertedValue;
         if (valueType.IsEnum)
         {
             Debug.Assert(valueType == value.GetType(), "The valueType should equal the Type of the value");
             convertedValue = value;
         }
         else
         {
             try
             {
                 if (stringValue != null)
                 {
                     convertedValue = Enum.Parse(this.EnumType, stringValue, true);
                 }
                 else
                 {
                     convertedValue = Enum.ToObject(this.EnumType, value);
                 }
             }
             catch (ArgumentException)
             {
                 // 
                 return false;
             }
         }

         if (IsEnumTypeInFlagsMode(this.EnumType))
         {
             string underlying = GetUnderlyingTypeValueString(this.EnumType, convertedValue);
             string converted = convertedValue.ToString();
             return !underlying.Equals(converted);
         }
         else
         {
             return Enum.IsDefined(this.EnumType, convertedValue);
         }
     }

     private static bool IsEnumTypeInFlagsMode(Type enumType)
            {
                return enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Length != 0;
            }


     private static string GetUnderlyingTypeValueString(Type enumType, object enumValue)
            {
                return Convert.ChangeType(enumValue, Enum.GetUnderlyingType(enumType), CultureInfo.InvariantCulture).ToString();
            }
 }

Source code reference: https://referencesource.microsoft.com/#System.ComponentModel.DataAnnotations/DataAnnotations/EnumDataTypeAttribute.cs,4c23e1f3dcd51167

Upvotes: 1

Related Questions