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.
Thanks for this blog post. I’m using the MVC 3 RC as my first introduction to MVC and I was getting stuck on this. The model level validation works but doesn’t seem very elegant. This is much better.
I did try to use Foolproof in my project, but it doesn’t seem to work with MVC 3. I think it has something to do with the new HTML 5 attributes only being allowed to be lowercase. I tried to open up the latest source code for Foolproof to see if I could fix it, but VS kept locking up when I tried to open the solution/project files.
So I think I’ll just wait for your new version. But thanks for your efforts!
Thanks for the heads up Shea, I hope to be looking into Foolproof for MVC 3 shortly.
Hi Nick,
Foolproof is awesome and handy! We’ve invested a lot of time on building an application with MVC2, and we are intending to continue using Foolproof. Could you help us with a problem I have encountered:
I have a function to help me do explicit validation of properties using reflection(code pasted below – hopefully it formats ok! ). Even though after model binding, ModelState is valid and all of the stock Validation attributes are passing this function and returning true in the end ( Required, Range etc…), when I add foolproof validation attributes to properties, this function fails validation despite ModelState being valid.
Any clues?
Sorry, after reading my own comment, I thought it needed to be better worded:
I have a function to help me do explicit validation of properties using reflection(code in the above comment).
The normal scenario is this:
When a request is posted to my action with my model, the model binding validates the model based on the data annotations. Lets say my ModelState is valid. In this case, when I call the my custom function above, it returns true as it should.
Enter Foolproof. Now, I have a few properties with Foolproof RequiredIfTrue attribute. Now, when the request is posted to my action, the model binding kicks in. Let us say my ModelState is valid. In this case though, when I call my custom function above, it returns false. This happens, despite the fact that ModelState is valid.
Please help.
Hi to every body, it’s my first pay a visit of this website; this webpage includes remarkable and genuinely fine information for visitors.
Attractive section of content. I just stumbled upon your blog and in accession
capital to assert that I get actually enjoyed account
your blog posts. Anyway I’ll be subscribing to your augment and even I achievement you access consistently rapidly.
I’m impressed, I have to admit. Rarely do I encounter a blog that’s both educative and interesting,
and let me tell you, you’ve hit the nail on the head. The issue is something that too few men and women are speaking intelligently about. Now i’m very happy that
I came across this during my hunt for something regarding this.
Thanks for the marvelous posting! I seriously enjoyed
reading it, you might be a great author.I will
ensure that I bookmark your blog and will eventually come back at some point.
I want to encourage you to ultimately continue your great posts, have a nice
weekend!
Wonderful blog! Do you have any suggestions for aspiring
writers? I’m hoping to start my own blog soon but I’m a little lost on everything.
Would you propose starting with a free platform like WordPress or go
for a paid option? There are so many choices out there that I’m totally confused .. Any tips? Many thanks!