Validation Interfaces

IValidationRuleProvider

Rules can be provided to a Validator in two ways. The first is to simply register an individual ValidationRule with the Validator using the RegisterRule() method.

SampleAsyncRule asyncRule = new SampleAsyncRule(3000);
validator.RegisterRule(this, asyncRule);

IValidationRuleProvider The second is to nominate an IValidationRuleProvider by adding it to the RuleProviders collection property. A RuleProvider is responsible for providing zero or more ValidationRules to the Validator when it is asked to validate an object instance for the first time. An example implementation is the EntityRuleProvider class which creates validation rules  by using TypeDescriptor methods to iterate over all Property and Type level Attributes searching for those that implement the IAttributeRuleProvider interface (see below).

// Create an EntityValidator for each business model class that requires validation.
EntityValidator holidayValidator = new EntityValidator();
// Register the entity with the validator - this will create all the necessary rules as
// determined by the rule Provider.
holidayValidator.RegisterEntity(_holiday, new EntityRuleProvider());

Alternatively a different IValidationRuleProvider could be used so that rather than defining validation rules declaratively using .NET Attributes they could be extracted from some external source, for example an XML config file.

IValidationValueProvider

IValidationValueProvider This interface is used by the ValidationRules themselves. When a rule is Validated by a Validator it is passed a single value. This value will be the instance that the Validator has been asked to Validate. For example an EntityValidator may use INotifyPropertyChanged to validate a business entity on every property change – and the business entity instance would be passed to the ValidationRule.

Implementations of the IValidationValueProvider allow the value that is to be validated to be derived immediately prior to the rule’s execution. If no IValidationValueProvider is assigned to the ValidationRule it will simply use the value passed by the Validator (e.g. the business entity). A very simple IValidationValueProvider is the PropertyValueProvider which simply uses a PropertyDescriptor to resolve the property value from the instance being validated for rules that act on a Property rather than a Type.

This could be extended for example by having a ControlValueProvider that extracts the value from an unbound User Interface control based on the type of control. This would allow validation at the control level in the rare cases where validation wasn’t being performed on Controller/Presenter elements.

In addition to providing a value this interface is also responsible for identifying the context in which any errors occurred. More on this below.

IAttributeRuleProvider

Each custom Attribute class is responsible for creating its own ValidationRule(s) via this interface. This makes declaratively defining new custom ValidationRules very easy.

IAttributeRuleProvider

The code below shows how the EntityRuleProvider implements IValidationRuleProvider.GetRules by making use of the IAttributeRuleProvider.

public ICollection<ValidationRule> GetRules(object value)
{
List<ValidationRule> rules = new List<ValidationRule>();
// Get a list of all properties defined on this object
    PropertyDescriptorCollection propertyDescriptors = TypeDescriptor.GetProperties(value);
// Iterate through the properties and pull of all the attribute defined validation rules
    foreach (PropertyDescriptor propertyDescriptor in propertyDescriptors)
{
foreach (Attribute attribute in propertyDescriptor.Attributes)
{
IAttributeRuleProvider attributeRuleProvider = attribute as IAttributeRuleProvider;
if (attributeRuleProvider != null)
{
ValidationRuleCollection newRules = attributeRuleProvider.GetRules(value, propertyDescriptor);
foreach (ValidationRule newRule in newRules)
{
newRule.ValueProvider = new PropertyValueProvider(propertyDescriptor);
newRule.DefaultMessageParameters.Add("value", propertyDescriptor.DisplayName);
rules.Add(newRule);
}
}
}
}
// Now pull the attribute defined validation rules off the class itself.
    foreach (Attribute attribute in TypeDescriptor.GetAttributes(value))
{
IAttributeRuleProvider attributeRuleProvider = attribute as IAttributeRuleProvider;
if (attributeRuleProvider != null)
{
ValidationRuleCollection newRules = attributeRuleProvider.GetRules(value, null);
foreach (ValidationRule newRule in newRules)
{
newRule.ValueProvider = null;
newRule.DefaultMessageParameters.Add("value", value.GetType().Name);
rules.Add(newRule);
}
}
}
return rules;
}

Note that by using PropertyDescriptor.DisplayName we get the “friendly” name of the property as can be provided via the System.ComponentModel.DisplayName attribute. This is important because its gets passed in as a “token” for optional use by the ValidationRule’s message, e.g. “The {value} is mandatory.” would automatically resolve {value} to the DisplayName.

ValidationContext

This abstract class is used to determine the context in which a ValidationRule failed. There are three concrete Context’s so far as shown below.

ValidationContext

Again, if User Interface Control level validation was required it would be easy to add a ControlContext class deriving from ValidationContext. One of the things that the ValidationContext is used for is displaying visual cues in the user interface to  indicate validation failure. For example a rule could be executed in the business tier (on an application server) and transmitted back to the client. The user interface can then use data binding (or some other method) to match the context to a relevant user interface element.