In the beta version of Foolproof, a new base class called ModelAwareValidationAttribute was added. This class serves as the base class for all Foolproof attributes but it also allows developers to create custom complex validation attributes in situations where access to the model is needed.
Here is an example:
We have a view model meant for c
reating a new user that has a Department and Role property. However we need to enforce some constraints around which roles a new user can be assigned to based on which department they are a member of. For example, only users that are in the “IT Department” can be in the “Software Developers” role.
Here is our view model:
public class CreateUserViewModel { [Required] public string Username { get; set; } [Required] public string Department { get; set; } [Required] public string Role { get; set; } }
Now it’s time to create new data annotation using Foolproof to enforce our business logic:
public class RoleValidInDepartmentAttribute : ModelAwareValidationAttribute { //this is needed to register this attribute with foolproof's validator adapter static RoleValidInDepartmentAttribute() { Register.Attribute(typeof(RoleValidInDepartmentAttribute)); } public override bool IsValid(object value, object container) { if (value != null && value.ToString() == "Software Developers") { //if the role was software developers, we need to make sure the user is in the IT department var model = (CreateUserViewModel)container; return model.Department == "IT Department"; } //the user wasn't in a constrained role, so just return true return true; } }
Now we can use our new attribute in our view model:
[Required] [RoleValidInDepartment(ErrorMessage="This role isn't valid for the selected department.")] public string Role { get; set; }
The results look good!
Update: I’ve posted how to create an accompanying client side validator.
Hey this is great. I was greatly dissapointed by the pathetic out-of-box offering for validation in MVC/MVC2 and was just about to start writing my own validation provider. This one however gives me a better starting point and is (now) extensible. Nice
Are there any plans for something like RegexIfAttribute, where a regex pattern (with optional RegexOptions) must pass successfully but only when a condition is met elsewhere in model?
I have an address model that needs to validate postal code for certain countries (e.g., Canadian “ANA NAN” and US ZIP[+4]) where that would be nice to do.
I tried to roll my own but, the further I got, the more it seemed I needed to bring the entire source with it to get access to all the internals; there was a close call when I tried to inherit from RequiredIfAttribute, but that ended up being functionally incorrect. I’m not opposed to writing such an attribute to contribute but I don’t want to step on any toes; it would also lack client-side validation until I brush up on implementing/testing that. If all else fails, I can make a bunch of custom address model-aware validation attributes.
Adam, I like that idea. I created a CodePlex work item for it:
http://foolproof.codeplex.com/WorkItem/View.aspx?WorkItemId=12918
Awesome. I was stunned to see that only the most simplistic validation scenarios were included in MVC2 by default. Glad I found this… it will help greatly.
[…] time to create the client side version because posting back sucks. Weeks ago, I covered how to build custom model-aware validators using Foolproof. I got a question about how to build an accompanying client side validator. So today I’ll cover […]
Thanks for Foolproof! Much appreciated.
I have an issue whereby my custom model validation (implementing ModelAwareValidationAttribute) works fine within the context of ASP.NET MVC, but I run into a NotImplementedException in Foolproof.ModelAwareValidationAttribute.IsValid when running a controller test. Any suggestions for how this be resolved?
jkjljjj
Awesome. Fantastic. It was really helpful.
[…] Build Model-Aware Custom Validation Attributes in ASP.NET MVC 2 […]