How to handle enum as string binding failure when enum value does not parse
We had this issue recently and wrote our own attribute to handle it:
public class ValidEnumValueAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
Type enumType = value.GetType();
bool valid = Enum.IsDefined(enumType, value);
if(!valid)
{
return new ValidationResult($"{value} is not a valid value for type {enumType.Name}");
}
return ValidationResult.Success;
}
}
class Person
{
public string Name {get; set;}
[ValidEnumValue]
public SexEnum Sex {get; set;}
}
The error is then added to the ModelState so you can use ModelState.IsValid
to check if the values are valid.
if(!ModelState.IsValid)
{
return BadRequest(ModelState);
}
EDIT
If you don't want to use an attribute then you can derive a new converter from NewtonSoft StringEnumConverter
and have that check the value is valid before reading the json e.g.
public class validEnumConverter : StringEnumConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if(!Enum.IsDefined(objectType, reader.Value))
{
throw new ArgumentException("Invalid enum value");
}
return base.ReadJson(reader, objectType, existingValue, serializer);
}
}
This is added to the JsonOptions in your startup class:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddJsonOptions(options =>
{
options.SerializerSettings.Converters.Add(new validEnumConverter());
});
}
Following up on Simply Ged's answer above, AFAICS, this actually cannot be done as the model binding exceptions are swallowed (https://github.com/aspnet/Mvc/issues/3898)
ModelState
contains model binding errors and you can get some information out of that. As we currently use only JSON serialization, I ended up implementing a filter to check the ModelState
errors for JsonSerializationException
. It is not perfect though as eg. to get the requested value (that failed the binding) out of the JsonSerializationException
you need to parse the inner exception message.
If someone finds a better solution, I will be happy to hear.