Validating Enum Values within C# MVC. Partial validation occurs - How to change validation behaviour?
Asked Answered
Z

1

22

I've been representing an enum within my razor view as a hidden field, which is posted back to an action result.

I've noticed that when it binds the string value provided within the HTML, it automatically validates the value for the enum.

/// <summary>
/// Quiz Types Enum
/// </summary>
public enum QuizType
{
    /// <summary>
    /// Scored Quiz
    /// </summary>
    Scored = 0,

    /// <summary>
    /// Personality Type Quiz
    /// </summary>
    Personality = 1
}

Razor:

@Html.HiddenFor(x => x.QuizType)

Rendered HTML:

<input data-val="true" data-val-required="Quiz Type is not valid" id="QuizType" name="QuizType" type="hidden" value="Scored">

If I change the value within the DOM to something incorrect and submit the form, ModelState.IsValid returns false and the following error is added to the ModelState:

"The value 'myincorrectvalue' is not valid for QuizType."

That's all gravy, but I thought that if I created a view model, that I had to explicitly set validation rules on my view model, such as the [Required] attribute.

Also there is a validation attribute specifically for this called EnumDataType.

[EnumDataType(typeof(QuizType))]
public QuizType QuizType { get; set; }

Question

If validation happens automatically when binding, what is the point in the EnumDataType data validation attribute?

Zacek answered 17/10, 2014 at 12:40 Comment(8)
An enum value is always required (it cant be null) so that why the validation is added. If you don't want it to be required, make it nullable public QuizType? QuizType { get; set; }Principal
Indeed, but I'm not setting it to null, I'm setting it to a value that is not contained in the EnumZacek
Also, int is non-nullable, but if I was to set it null it would just be bound as 0... so that doesn't perform auto-validation. Where is it documented which types do/do-not get auto validated?Zacek
I've just tried setting an int to an arbitrary string value and it came up with a similar error. I think it must come up with this error for any value that is set to an incorrect value for the type, but it seems that the binding explicitly checks the string value sent from the HTML against the actual text within the enum. If I hadn't have set the value within the HTML at all, then this error wouldn't have been set automatically.Zacek
Yes it does. If you bind a textbox to an int and clear the textbox, you will get a validation error (inspect the html and you will see <input data-val="true" data-val-required="The ID field is required." ...> even if you dont add the [Required] attributePrincipal
This leads me to wonder why there are questions like this floating around #14382064 if the validation is automatic upon binding?Zacek
Please see my answer below as I've figured it out.Zacek
Good for your and +1 from me :)Principal
Z
49

Ok, so I've found out the answer to my own question.

The error message that appeared is more of a generic error message for when the binding wasn't possible. When the binding attempts to bind a non-existent string representation of the enum value posted from the HTML to the enum, it produces the error:

The value 'myincorrectvalue' is not valid for QuizType.

The exact same error message would appear if I were to attempt to bind a string value to an int within my View Model class.

It seems that the issue is that as well as the string representation, an enum can be any integer value. I can set the enum to any number, even if that number doesn't exist within my enum.

/// <summary>
/// Quiz Types Enum
/// </summary>
public enum QuizType
{
    /// <summary>
    /// Scored Quiz
    /// </summary>
    Scored = 0,

    /// <summary>
    /// Personality Type Quiz
    /// </summary>
    Personality = 1
}

Therefore, this is valid and will be bound without error to my enum value, even though 1000 doesn't exist within my enum:

<input data-val="true" id="QuizType" name="QuizType" type="hidden" value="1000">

//  Binder will bind this just fine
QuizType = 1000

That's where the EnumDataType validation attribute comes in. If I add the validation attribute to my enum within my view model:

[EnumDataType(typeof(QuizType), ErrorMessage = "Quiz type value doesn't exist within enum")]
public QuizType QuizType { get; set;}

With the attribute in place, I will only be able to assign my valid enum values (0 or 1 for this example).

So the incorrect STRING representations posted from the HTML is validated for you automatically upon binding, but a check for any integer value will not.

I hope that this clears up validating ENUMS within ASP.NET MVC.

Zacek answered 17/10, 2014 at 13:13 Comment(1)
I'm really glad to have helped! This puzzled me for a while.Zacek

© 2022 - 2024 — McMap. All rights reserved.