3

Does there exist an enum validation attribute which validates a certain enum value?

Or should I do that manually:

if(viewModel.State == State.None) base.AddModelError("","wrong enum selected...");

How would you do that?

3
  • is there an issue with doing it this way? are you looking for attribute validation instead? I'm sure you could define your own attribute that would give you this kind of functionality Commented Mar 26, 2015 at 16:10
  • No issue am just looking for best practice here. Or someone did that attribute already or I can not find it in latest mvc ;-) Commented Mar 26, 2015 at 16:12
  • Why would you include a enum value in the view that is not valid (your just cofusing the user)? Make the property [Required]public State? State { get; set; } and include only valid values in enum State (and if that enum is being used elsewhere, then use a view model). Alternatively you would need a custom validation attribute that accepts an array of valid (or invalid) names, something like [RequiredEnum(Exclude="None")]public State? State { get; set; } Commented Mar 27, 2015 at 0:18

3 Answers 3

4

Enum:

public enum SomeEnum
{
    Right = 1,
    Wrong = 2,
    Other = 3
}

ViewModel:

public class TestModel
{
    [Range((int)(SomeEnum.Right), (int)(SomeEnum.Right), ErrorMessage = "Please select an Enum value")]
    public SomeEnum Value { get; set; }
}

No other code needed. Enums are basically integers so you can use the Range attribute to validate them.

Sign up to request clarification or add additional context in comments.

Comments

2

I would create my own validation attribute something like (untested):

public enum SomeEnum
{
    Right,
    Wrong
}


[AttributeUsage(AttributeTargets.Property)]
public sealed class EnumValueAttribute : ValidationAttribute
{
    private const string DefaultErrorMessage = "Cannot be that value";

    public SomeEnum EnumVal { get; private set; }

    public EnumValueAttribute(SomeEnum enumVal)
        : base(DefaultErrorMessage)
    {
        EnumVal = enumVal;
    }

    public override string FormatErrorMessage(string name)
    {
        return string.Format(ErrorMessageString, name, EnumVal);
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var enumVal = (SomeEnum) Enum.Parse(typeof (SomeEnum), value.ToString());
        if (enumVal != EnumVal)
        {
            return new ValidationResult(DefaultErrorMessage);
        }

        return ValidationResult.Success;
    }
}

Usage:

public class TestModel
{
    [EnumValue(SomeEnum.Right)]
    public SomeEnum Value { get; set; }
}

UPDATED

So this is as generic as you can reasonably take it, I've not tested this code, but it does compile. Notice that I've assigned number values to the enums.

public enum SomeEnum
{
    Right = 1,
    Wrong = 2,
    Other = 3
}


[AttributeUsage(AttributeTargets.Property)]
public sealed class DisallowEnumValueAttribute : ValidationAttribute
{
    public object DissallowedEnum { get; private set; }
    public Type EnumType { get; private set; }

    public DisallowEnumValueAttribute(Type enumType, object dissallowedEnum)
    {
        if (!enumType.IsEnum)
            throw new ArgumentException("Type must be an enum", "enumType");

        DissallowedEnum = dissallowedEnum;
        EnumType = enumType;
    }


    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var disallowed = Convert.ChangeType(DissallowedEnum, EnumType);
        var enumVal = Convert.ChangeType(value, EnumType);

        if (disallowed == null || enumVal == null)
            throw new Exception("Something is wrong"); //or return validation result

        if (enumVal == disallowed)
        {
            return new ValidationResult("This value is not allowed");
        }

        return ValidationResult.Success;
    }
}

public class TestModel
{
    [DisallowEnumValue(typeof(SomeEnum), SomeEnum.Wrong)]
    public SomeEnum Thing { get; set; }
}

2 Comments

Would it be possible to make this Attribute generically working as public SomeEnum EnumVal { get; private set; } seems to be hardcoded. If I should do this effort of creating an attribute it must work generically else its waste of time then I would rather use my oneliner...
Not in MVC - it needs all fields to be mutable when deserializing models.
0

My enum validation was like this and works in dataannotation validation

public enum CreatedBySelfOrOthersEnumValues
{
    Self,
    Others
}

  
public class CampaignRegisterValidationModel
{
    [Required]
    public string Name { get; set; }

    [Required]
    public CreatedBySelfOrOthersEnumValues CreatedForSelfOrOthers { get; set; }

    [Required]
    public int CountryCode { get; set; }

    public string Phone { get; set; }
    public string Email { get; set; }
}

Then validating it

if (ModelState.IsValid)
{

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.