Creating New Data Annotation Validation Attributes
Valid for the following versions: ASP.NET MVC 2
Though the DataAnnotations attributes were usable in the first version of ASP.NET MVC, how they are used in version 2 is a bit different. This tutorial may only apply to ASP.NET MVC 2.
We just looked at how to use the DataAnnotations validation attributes, but what if those aren't enough? Fortunately, new validation attributes are easy to create.
Option 1: Inherit from ValidationAttribute
The base class for the validation attributes (Range, StringLength, etc.) is System.ComponentModel.DataAnnotations.ValidationAttribute. The class has one abstract method, all you may need to make your validation attribute. Here is an example of a rather unuseful implementation of a validation attribute.
using System;
using System.ComponentModel.DataAnnotations;
namespace Some.Really.Awesome.Namespace
{
public class DoesNotContainKerfuffleAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value == null)
return true;
if (value.ToString().Contains("Kerfuffle"))
return false;
else
return true;
}
}
}
And that is it. All this attribute does is make sure the string "Kerfuffle" is not contained in the value. If it is, a false (meaning "this is not valid") is returned. If you wanted a more generic attribute that allowed you to specify the word, you could pass that in as a constructor argument. Or perhaps you could pass in an array of words that are not allowed. The what and the how will be limited only by your imagination. But that is how simple it is to create your own validation attribute.
Option 2: Inherit from RegularExpressionAttribute
I believe a fertile source for useful validation attributes can through inheriting from the RegularExpressionAttribute instead of its base ValidationAttribute as we did in the last example. Let's say you wanted to validate that a property was a roman numeral. Would you rather see...
[RegularExpression("^(?i:(?=[MDCLXVI])((M{0,3})((C[DM])|(D?C{0,3}))?((X[LC])|(L?XX{0,2})|L)?((I[VX])|(V?(II{0,2}))|V)?))$", ErrorMessage = "Not a roman numeral.")]
public string ARomanNumeralField { get; set; }
or...
[IsARomanNumeral(ErrorMessage = "Not a roman numeral.")]
public string ARomanNumeralField { get; set; }
...when you look at your view model? No question. Here is how you could inherit from the RegularExpressionAttribute to make creating this validation attribute easy:
using System;
using System.ComponentModel.DataAnnotations;
namespace Some.Really.Awesome.Namespace
{
public class IsARomanNumeralAttribute : RegularExpressionAttribute
{
private const string _REGEX = "^(?i:(?=[MDCLXVI])((M{0,3})((C[DM])|(D?C{0,3}))?((X[LC])|(L?XX{0,2})|L)?((I[VX])|(V?(II{0,2}))|V)?))$";
public IsARomanNumeralAttribute()
: base(_REGEX)
{
}
}
}
The real work is being done by parent class. All that this new attribute needs to supply is the regular expression.
Conclusion
Fortunately, you are not limited to the attributes in the System.ComponentModel.DataAnnotations namespace. Creating new attributes that are automatically picked up by the validation process of the DefaultModelBinder is easy. Just inherit from the base validation attribute or one of the existing implementations and rock on.
Speak Your Mind!
Have something to say? Find a grammatical mistake? Think I said something incorrect? Don't like my perspective? Hate my color scheme? Whatever it is, you can let me know. I would appreciate it if you did.
