Introduction
The Validation block in Microsoft Enterprise Library 5.0 is used to define validation rules and manage them easily in different ways across applications.
It includes a comprehensive number of built-in validators including null
validation, range validation, self validation, etc. It also provides a superior way to validate the objects against predefined rules and provides the results with valuable information.
In addition to common validation mechanism, it supports technology specific validation for WPF, WCF and ASP.NET.
In this article, I will focus on the common tasks in validation block and try to explain them with examples. I developed a demo application for testing validations and you find the examples in it and find out how it works. The examples are taken from the demo project and developed using Microsoft Visual Studio 2010, .NET Framework 4.0, and Microsoft Enterprise Library 5.0.
You can obtain Microsoft Enterprise Library assembly files and other relevant resources from the following address:
Basics
There are 3 types of validators in validation block:
- Value validators
- Composite validators
- Object validators
Value validators: Perform specific validations such as validating the length of string
, checking if the value is null
or not, and validating the number against a predefined range.
Composite validators: Allow to combine with other validators to create a complex set of validations. Two types of composite validations exist: AND
validator and OR
validator. By using these composite validators with other validators, it is possible to define the validation logic between the validators.
Object validators: Perform all validations defined for the type and supports the validation against the objects in collections.
Preparation
To use the validation block, you must reference the required assemblies. The main validation block assembly is Microsoft.Practices.EnterpriseLibrary.Validation.dll.
If you intend to use the integration features for ASP.NET, Windows Forms, WPF or WCF, you must also reference the relevant assembly from the list below that contains these features:
- For ASP.NET, Microsoft.Practices.EnterpriseLibrary.Validation.Integration.AspNet.dll
- For Windows Forms, Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WinForms.dll
- For WPF, Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WPF.dll
- For WCF, Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF.dll
How to Use Validation Block
Firstly, you must initialize a validator instance which you use to create and execute validations through the following lines:
ValidatorFactory valFactory =
EnterpriseLibraryContainer.Current.GetInstance<ValidatorFactory>();
In the lines above, the Unity dependency injection mechanism is used to create the objects related with validations. However, it is possible to use another Dependency Injection mechanism for different purposes if you prefer through an implementation of the IServiceLocator
interface.
Let’s create our customer to be used for validation:
public class AttributeCustomer
{
[NotNullValidator(MessageTemplate = "Customer must have valid no")]
[StringLengthValidator(5, RangeBoundaryType.Inclusive,
5, RangeBoundaryType.Inclusive,
MessageTemplate = "Customer no must have {3} characters.")]
[RegexValidator("[A-Z]{2}[0-9]{3}",
MessageTemplate = "Customer no must be 2 capital letters and 3 numbers.")]
public string CustomerNo { get; set; }
}
Then, we create a required validator depending on our validation preference. In this context, we prefer validation block attributes approach.
Validator<AttributeCustomer> cusValidator =
valFactory.CreateValidator<AttributeCustomer>();
We initialize our customer
object which requires validations and validate it through the attributes defined in the customer
object type.
var customer = new AttributeCustomer();
customer.CustomerNo = "AB123";
customer.FirstName = "Brown";
customer.LastName = "Green";
customer.BirthDate = "1980-01-01";
customer.CustomerType = "VIP";
ValidationResults valResults = cusValidator.Validate(customer);
Lastly, we have validations results and we can check if the object is valid. If it is not valid, we can find the reasons why the validation fails and the failure sources (object property in this context).
if (valResults.IsValid)
{
MessageBox.Show("Customer information is valid");
}
else
{
foreach (ValidationResult item in valResults)
{
}
}
Approaches
There are five validation approaches which you can prefer during validations. Each one has advantages and disadvantages over each other, but I do not focus on these details now. Also, it is possible to apply multiple approaches at the same time. For example, you can implement self validation and data annotation attributes approaches at the same time, which gives you much flexibility.
- Rule sets in configuration
- Validation block attributes
- Data annotation attributes
- Self-validation
- Validators created programmatically
Rule sets in Configuration
In this approach, we put our validation rules into the configuration file (web.config in ASP.NET and app.config in Windows applications). Here is an example showing how to define validation rules:
="1.0"="utf-8"
<configuration>
<configSections>
<section name="validation" type="Microsoft.Practices.EnterpriseLibrary.
Validation.Configuration.ValidationSettings,
Microsoft.Practices.EnterpriseLibrary.Validation, Version=5.0.414.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
</configSections>
<validation>
<type name="ELValidation.Entities.BasicCustomer"
defaultRuleset="BasicCustomerValidationRules"
assemblyName="ELValidation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<ruleset name="BasicCustomerValidationRules">
<properties>
<property name="CustomerNo">
<validator type="Microsoft.Practices.EnterpriseLibrary.
Validation.Validators.NotNullValidator,
Microsoft.Practices.EnterpriseLibrary.Validation"
negated="false" messageTemplate="Customer must have valid no"
tag="CustomerNo" name="Not Null Validator" />
<validator type="Microsoft.Practices.EnterpriseLibrary.
Validation.Validators.StringLengthValidator,
Microsoft.Practices.EnterpriseLibrary.Validation"
upperBound="5" lowerBound="5" lowerBoundType="Inclusive"
upperBoundType="Inclusive"
negated="false" messageTemplate="Customer no must have {3} characters."
tag="CustomerNo" name="String Length Validator" />
<validator type="Microsoft.Practices.EnterpriseLibrary.
Validation.Validators.RegexValidator,
Microsoft.Practices.EnterpriseLibrary.Validation"
pattern="[A-Z]{2}[0-9]{3}" options="None" patternResourceName=""
patternResourceType=""
messageTemplate="Customer no must be 2 capital letters and 3 numbers."
messageTemplateResourceName="" messageTemplateResourceType=""
tag="CustomerNo" name="Regex Validator" />
</property>
</properties>
</ruleset>
</type>
</validation>
</configuration>
In our configuration file, we first define a config section for Enterprise Library validation settings. Then, we define our validation rules as shown in the example. First, define the type to which rules are applied through “type
” tag and define each property for the type and relevant validations for the property.
We can write our validation rules manually or do it through Enterprise Library Configuration tool which is most probably located in the following path:
Program Files Folder\Microsoft Enterprise Library 5.0\Bin\EntLibConfig.NET4.exe
This tool helps you much and prevents you from the complexities during configuration because it can be hard to do it manually.
In this example, we define a ruleset name, BasicCustomerValidationRules
, which is used to validate our object against specific rules as shown in the following lines:
public class BasicCustomer : ICustomer
{
public string CustomerNo { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string BirthDate { get; set; }
public string CustomerType { get; set; }
}
Validator<BasicCustomer> cusValidator =
valFactory.CreateValidator<BasicCustomer>("BasicCustomerValidationRules");
ValidationResults valResults = cusValidator.Validate(customer);
We test the customer
object if the value of the customerno
is not null
, it has exactly 5 characters, and it has a similar format like AB123.
Validation Block Attributes
In this approach, we define our validations through the attributes defined in Enterprise Library validation block.
[NotNullValidator(MessageTemplate = "Customer must have valid no")]
[StringLengthValidator(5, RangeBoundaryType.Inclusive,
5, RangeBoundaryType.Inclusive,
MessageTemplate = "Customer no must have {3} characters.")]
[RegexValidator("[A-Z]{2}[0-9]{3}",
MessageTemplate = "Customer no must be 2 capital letters and 3 numbers.")]
public string CustomerNo { get; set; }
In this example, we check if the customerno
is not null
, it has exactly 5 characters, and it has a similar format like AB123.
Also, message template is a good way to provide meaningful messages on failure with the flexibility to be replaced by Enterprise Library validation block for brackets.
In this example, if the number of characters in CustomerNo
is different from 5
, we get the error message like Customer no must have 5 characters
.
Data Annotation Attributes
In this approach, we define our validations through the attributes defined within System.ComponentModel.DataAnnotations
assembly.
In the following example, we define 3 validation rules for CustomerNo
property, so that it cannot be null
, it must have exactly 5 characters, and the format of the CustomerNo
should be like this AB123
.
[Required(ErrorMessage = "Customer no can not be empty")]
[StringLength(5, ErrorMessage = "Customer no must be 5 characters.")]
[RegularExpression("[A-Z]{2}[0-9]{3}",
ErrorMessage = "Customer no must be 2 capital letters and 3 numbers.")]
public string CustomerNo { get; set; }
This approach is widely used in conjunction with Entity Framework and ASP.NET validations.
Self-validation
This approach gives much flexibility to us in order to create and execute complex validation rules.
In order to implement this approach, we first decorate HasSelfValidation
attribute with the object type as shown in the following example:
[HasSelfValidation]
public class AttributeCustomer
{
…
}
Then, we write our validation logic by putting SelfValidation
attribute on the top of the method which executes the validations.
[SelfValidation]
public void Validate(ValidationResults validationResults)
{
var age = DateTime.Now.Year - DateTime.Parse(BirthDate).Year;
if (age < 18)
{
validationResults.AddResult(
new ValidationResult("Customer must be older than 18",
this,
"BirthDate",
null,
null));
}
}
In this example, we check BirthDate
property value if the customer is bigger than 18 or not, then append the validation results to validation result collection on failure.
Validators Created Programmatically
This approach is different from the others because validation rules are created programmatically and executed independent of the type.
First, we define our validation rules:
Validator[] validators = new Validator[]
{
new NotNullValidator(false, "Value can not be NULL."),
new StringLengthValidator(5, RangeBoundaryType.Inclusive,
5, RangeBoundaryType.Inclusive, "Value must be between {3} and {5} chars.")
};
Then, we add them into one of the composite validators depending on your preference.
var validator = new AndCompositeValidator(validators);
Lastly, we execute the validation rules against our object to be tested and get the results.
ValidationResults valResults = validator.Validate("Value to be tested…");
In this example, we check Value to be tested…
if it is not null
and it has five exact characters.
Finally, I want to mention about the validations against collections. Actually, it is similar to the validations for objects.
var customer = new AttributeCustomer();
FillCustomerInfo(customer);
List<AttributeCustomer> customers = new List<AttributeCustomer>();
customers.Add(customer);
Validator cusValidator = new ObjectCollectionValidator(typeof(AttributeCustomer));
ValidationResults valResults = cusValidator.Validate(customers);
ShowResults(valResults);
Final Words
The validation block is very powerful and saves much time really. Also, it is easy to implement and maintain the validations. Of course, the validation block is larger than what I try to illustrate in this article, but I expect that you will understand how it works and start to use in your applications. Lastly, Microsoft Enterprise Library 5.0 has integration features for ASP.NET, Winforms, WPF, and WCF. I will focus on these integration features in my next articles.
History
- 18th September, 2011: Initial version