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