Friday, April 11, 2008

Enterprise Library 3.1 – Validation Application Block

Any application that accepts input either from users or from other systems must ensure that the information is valid in terms of some set of rules that you specify. The Validation Application Block provides the functionality necessary to validate .NET Framework data types. The data type validation is performed by a series of classes called validators.

The Validation Application Block is designed to address the most common tasks developers face when they must validate input either from a user or another system. These tasks are arranged according to scenarios. Each scenario gives an example of a typical way to use the Validation Application Block and shows the code that accomplishes the task.

The scenarios are the following:

• Using attributes to define validation rules
• Using configuration to define validation rules
• Validating objects
• Using self validation to define validation rules within your classes

Integrating the Validation Application Block into the following types of applications:

• ASP.NET
• Windows Forms
• WCF

Validator Class
The core component of the Validation Application Block is the Validator class. This class is the base class from which all validators inherit. The Validator class contains an overloaded method called Validate. The purpose of the Validate method is to validate a given object and determine whether or not it passes validation based on the rules of the validator.

public abstract class Validator<T> : Validator
{
protected Validator(string messageTemplate, string tag);

protected internal override void DoValidate(object objectToValidate, object currentTarget, string key, ValidationResults validationResults);
protected abstract void DoValidate(T objectToValidate, object currentTarget, string key, ValidationResults validationResults);

public ValidationResults Validate(T target);

public void Validate(T target, ValidationResults validationResults);
}


ValidationResults Class
The ValidationResult class represents specific results returned by a Validator instance. When a Validator instance determines that a rule is violated, a new instance of ValidationResult is created and added to the ValidationResults collection. The ValidationResults class provides a collection of validation results that were processed during the validation of an object. If validation results were returned, then one or more rules were broken during the validation process.

[Serializable]
public class ValidationResults : IEnumerable<ValidationResult>, IEnumerable
{
public ValidationResults();

public bool IsValid { get; }
public void AddAllResults(IEnumerable<ValidationResult> sourceValidationResults);
public void AddResult(ValidationResult validationResult);
public ValidationResults FindAll(TagFilter tagFilter, params string[] tags);
}


The ISValid Property returns True if the count of ValidataionResult instances in the collection is 0. Otherwise it returns False. We can find whether the validation is passed or not by checking the IsValid property of the ValidationResults class.

ValidationFactory Class
This class is responsible for creating a specific Validator class instance.

public static class ValidationFactory
{

public static Validator<T> CreateValidator<T>();
public static Validator<T> CreateValidator<T>(IConfigurationSource configurationSource);
public static Validator<T> CreateValidator<T>(string ruleset);
public static Validator CreateValidator(Type targetType);
public static Validator<T> CreateValidator<T>(string ruleset, IConfigurationSource configurationSource);
public static Validator CreateValidator(Type targetType, string ruleset);
public static Validator CreateValidator(Type targetType, string ruleset, IConfigurationSource configurationSource);
public static Validator<T>CreateValidatorFromAttributes<T>();
public static Validator<T> CreateValidatorFromAttributes<T>(string ruleset);
public static Validator CreateValidatorFromAttributes(Type targetType, string ruleset);
public static Validator<T> CreateValidatorFromConfiguration<T>();
public static Validator<T>CreateValidatorFromConfiguration<T>(IConfigurationSource configurationSource);
public static Validator<T> CreateValidatorFromConfiguration<T>(string ruleset);
public static Validator<T> CreateValidatorFromConfiguration<T>(string ruleset, IConfigurationSource configurationSource);
public static Validator CreateValidatorFromConfiguration(Type targetType, string ruleset);
public static Validator CreateValidatorFromConfiguration(Type targetType, string ruleset, IConfigurationSource configurationSource);
public static void ResetCaches();
}


The three overloaded methods, CreateValidator<T>, CreateValidatorFromConfiguration<T>, CreateValidatorFromAttributes<T> creates the validator instances based on the request.

Creating an Instance of the Validator Class via the ValidationFactory Class
For incorporating Validation Application Block in .NET application we need to add references to the following assemblies

• Microsoft.Practices.EnterpriseLibrary.Validation
• Microsoft.Practices.EnterpriseLibrary.Validation.Validators
• Microsoft.Practices.EnterpriseLibrary.Common.dll

If you are using the ASP.NET, Windows Forms, or WCF integration assemblies, add one of the following references as appropriate.

• Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WinForms.dll
• Microsoft.Practices.EnterpriseLibrary.Validation.Integration.AspNet.dll
• Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF.dll

Validation application block comes with three main categories of validators. Object validators, Composite validators and Basic validators.


public class Employee
{
[ValidatorComposition(CompositionType.And)]
[StringLengthValidator(1, 50, Ruleset = "RuleSetA", MessageTemplate = "First Name must be between 1 and 50 characters")]
[NotNullValidator( MessageTemplate="Name cannot be null", Ruleset="RuleSetA")]
public String Name { get; set; }

[RangeValidator(20, RangeBoundaryType.Inclusive, 55, RangeBoundaryType.Inclusive, Ruleset="RuleSetA", MessageTemplate= "Age must be between 20 and 55")]
public Int32 Age { get; set; }

[RegexValidator(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", MessageTemplate="Invalid e-mail address", Ruleset = "RuleSetA")]
public String Email { get; set; }

[RangeValidator(2000D, RangeBoundaryType.Exclusive, 0D, RangeBoundaryType.Ignore, Ruleset="RuleSetA", MessageTemplate="Salary should be minimum 2000")]
public Double Salary { get; set; }

[DateTimeRangeValidator("1978-01-01T00:00:00", "2008-01-01T00:00:00", MessageTemplate="Joining date should be between 01-01-1978 and 01-01-2008", Ruleset="RuleSetA")]
public DateTime DOJ { get; set; }
}


The above code sample defines a class Employee that includes a number of properties such as Name, Age, Salary, DOJ (Date of Joining), Email. Attributes that are attached to these properties associate them with validators. For example, the StringLengthValidator, NotNullValidator, ValidatorComposition attribute is attached to the Name property and associates it with the respective StringLengthValidator, NotNullValidator, ValidatorComposition class. Each validator has an additional NamedParameter set like MessageTemplate and RuleSet that defines the message template to show when the validation is failed and the rule set to valdiate respectively.
The Ruleset parameter of the validation attributes indicates that the application block will use "RuleSetA" rather than the anonymous, default rule set.
Once you have the validators and rule sets, you can validate your objects. The easiest way to do this is to use the Validation facade. The facade is responsible for creating the validator instance to validate the objects.

Employee emp = new Employee
{
Name = "Brian Williams”,
Age = 34,
DOJ = Convert.ToDateTime("07/07/2000"),
Email = "brian.williams@someserver.com",
Salary = 9990D
};
Validator<Employee> validator = ValidationFactory.CreateValidator<Employee>("RuleSetA");
ValidationResults results = validator.Validate(emp);

if (results.IsValid)
MessageBox.Show("Valid");
else
MessageBox.Show("Not Valid");

No comments: