For this to work using the attribute approach as discussed
previously (where each validator is defined as an attribute of the property it
will validate), the validator entity requires two classes. First, it requires
the interface of the actual validator itself, which inherits from the several
base classes available. Secondly, it requires the creation of an attribute
class (inherited from ValidatorAttribute), which handles exposing properties
through the constructor and the creation of the validator class. To create a
custom validator, there are several classes you can inherit from, and the ones
I will illustrate are the Validator, ValueValidator, and DomainValidator
classes. These are all generic implementations, but there are non-generic
versions as well.
Validators use the DoValidate method to perform validation,
which passes a reference to the value being evaluated, the source control, a
key representing the property being validated, and a collection object that
every validation result can be added to. With the generic implementation, the
object being validated is of the correct generic type, making this method more
type-specific. In addition to overriding the DoValidate method, a default
message property is usually required. The base Validator class has a single
method, whereas the ValueValidator has a non-negated and a negated version of
the default message. The DomainValidator class handles these methods so you do
not need to override it; you just need to provide the data at constructor time.