MVC4 WebAPI reject invalid enum values

2020-06-08 12:46发布

How can I make JSON.NET / MVC 4 WebAPI reject integer values for which the enum has no member? Eg:

If I have this model:

public enum Colour { Red = 1 };

public class Model
{
  public Colour Colour { get; set; }
}

Model Post(Model model)
{
   // model.Colour could be 99, 34234234, 0 etc, etc
}

If I post { Color: 9999 }, I end up with a model where model.Color = 999 and I want to return a Bad Request status code instead.

2条回答
我想做一个坏孩纸
2楼-- · 2020-06-08 13:34

One option is to write a validator:

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(String.Format("{0} is not a valid value for type {1}", value, enumType.Name));
        }
        return ValidationResult.Success;
    }
}

Use as:

public enum Color {Red = 1, Blue = 2}

public class Car
{
    [ValidEnumValue]
    public Color Color { get; set; }
}

In the controller, ModelState.IsValid would be false.
You can also throw a ValidationException, if you really want to fail the request, but I'm not quite sure that is how they should be used.

查看更多
Animai°情兽
3楼-- · 2020-06-08 13:38

It turns out the EnumDataTypeAttribute, which comes with the out-of-the-box ValidationAttributes in the System.ComponentModel.DataAnnotations namespace, does an Enum.Defined check.

Once I applied this attribute to my view model, out-of-range integer values failed validation:

public enum Color {Red = 1, Blue = 2}

public class Car
{
    [EnumDataType(typeof(Color))]
    public Color Color { get; set; }
}

Note: values that can be parsed into integers that are defined on the enum will still pass validation due to the default behavior of enum model binding. This means, for example, true will be parsed as 1, which would be valid for this enum. I assume characters that can be mapped to integers will also work.

If you only want one flavor of enum parsing to work, be it string or integer, consider using that specific type on your view model, and then write a custom ValidationAttribute that takes in the enum type, validating that the string or integer on your view model matches a value in the enum.

查看更多
登录 后发表回答