Nick Riggs, Web Developer

Making stuff up about web development since last week.

1 October 2014

Subscribe to our RSS feed

Posted in Foolproof January 20, 2010

MVC 3 gives us the ability to create model-aware validation attributes. What does this mean for Foolproof Validation

About a year ago I introduced the open source project Foolproof Validation for the purpose of adding contingent model-aware data annotation validation to ASP.NET MVC. I’m happy to say that ASP.NET MVC

3 will address the problem out of the box.

Pre MVC 3, if you needed an annotation to be model-aware, meaning that it needed knowledge of more than one property, you had to place that annotation on the class instead of property. This resulted in some undesirable effects, most notably that the model would fail validation instead of the particular property. Take for example PropertiesMustMatchAttribute in the stock MVC 2 application: It was placed on the ChangePasswordModel and RegisterModel classes, not the ConfirmPassword property of the models. This resulted in the validation messages being displayed in the summary and not beside the input box:

Enter MVC 3’s stock application. Notice they have created a custom CompareAttribute and instead of annotating the class, they annotate the ConfirmPassword property:

[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }

Which results in:

Much better! The magic in the CompareAttribute is in the IsValid function:

protected override ValidationResult IsValid(object value, ValidationContext context)
{
    var confirmValue = context.ObjectType.GetProperty(ConfirmProperty).GetValue(context.ObjectInstance, null);
    if (!Equals(value, confirmValue))
    {
        return new ValidationResult(FormatErrorMessage(context.DisplayName));
    }
    return null;
}

So the context parameter is your model. It uses reflection to get value of the property it’s comparing against, and then Equals is called using both property values. If Equals fails, a ValidationResult is returned with the error message.

This is a great addiction to the MVC framework. I haven’t completely decided how this will affect Foolproof in the future. Foolproof still provides a lot of value by providing several out of the box annotations that come up quite frequently, such as [GreaterThan] and [RequiredIf] – along with accompanying JavaScript validation. I suspect a fork will be in order, and the MVC 3 fork will utilize the new architecture while still providing a set of useful annotations and JavaScript.