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.