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

Time:12-23

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?

CodePudding user response:

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

  • Related