In this section, we cover three topics that you
should be familiar with when you start to use the block in your
applications: preparing your application to use the block, choosing a
suitable approach for validation, the options available for creating
validators, accessing and displaying validation errors, and
understanding how you can use template tokens in validation
messages.
Preparing Your Application
To use the Validation block, you must reference the required
assemblies. In addition to the assemblies required in every
application that uses Enterprise LibraryYou require the
main Validation block assembly, 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 that
contains these features.
Then you can edit your code to specify the namespaces used by
the Validation block and, optionally, the integration features if you
need to integrate with WCF or a UI technology.
Note
If you are using WCF integration, you should add a
reference to the System.Service Model namespace.
Choosing a Validation Approach
Before you start to use the Validation block, you should
consider how you want to perform validation. As you've seen,
there are several approaches you can follow. Table 1 summarizes these, and will help you
to choose one, or a combination, most suited to your
requirements.
Table 1. Validation approaches
Validation approach |
Advantages |
Considerations |
---|
Rule sets in
configuration |
Supports the full capabilities of the Validation
block validators.
Validation rules can be changed
without requiring recompilation and redeployment.
Validation rules are more visible and easier to
manage. |
Rules are visible in configuration files unless
the content is encrypted.
May be open to
unauthorized alteration if not properly protected.
Type definitions and validation rule definitions are
stored in different files and accessed using different tools,
which can be confusing. |
Validation block
attributes |
Supports the full capabilities of the Validation
block validators.
Validation attributes may be
defined in separate metadata classes.
Rules can
be extracted from the metadata for a type by using
reflection. |
Requires modification of the source code of the
types to validate.
Some complex rule combinations
may not be possible—only a single And or Or combination is available for
multiple rules.
Hides validation rules from
administrators and operators. |
Data annotation
attributes |
Allows you to apply validation rules defined by
.NET data annotation attributes, which may be defined in
separate metadata classes.
Typically used with
technologies such as LINQ, for which supporting tools might be
used to generate code.
Technologies such as
ASP.NET Dynamic Data that use these attributes can perform
partial client-side validation.
Rules can be
extracted from the metadata for a type by using
reflection. |
Requires modification of the source code.
Does not support all of the powerful validation
capabilities of the Validation block. |
Self-validation
|
Allows you to create custom validation rules that
may combine values of different members of the
class. |
Requires modification of the source code.
Hides validation rules from administrators and
operators.
Rules cannot be extracted from the
metadata for a type by using reflection. |
Validators created
programmatically |
A simple way to validate individual values as
well as entire objects.
Useful if you only need
to perform small and specific validation tasks, especially on
value types held in variables. |
Requires additional code and is generally more
difficult to manage for complex validation scenarios.
Hides validation rules from administrators and
operators.
More difficult to administer and
manage. |
If you decide to use attributes to define your validation rules within classes but are finding it
difficult to choose between using the Validation block attributes and
the Microsoft .NET data annotation attributes, you should consider
using the Validation block attributes approach as this provides more
powerful capabilities and supports a far wider range of validation
operations. However, you should consider the data annotations
approach in the following scenarios:
-
When you are working with existing applications that already
use data annotations. -
When you require validation to take place on the
client. -
When you are building a Web application where you will use
the ASP.NET Data Annotation Model Binder, or you are using ASP.NET
Dynamic Data to create data-driven user interfaces. -
When you are using a framework such as the Microsoft Entity
Framework, or another object/relational mapping (O/RM) technology
that auto-generates classes that include data annotations.
Options for Creating Validators Programmatically
There are several ways that you can create the validators you
require, whether you are creating a type validator that will validate
an instance of your class using a rule set or attributes, or you are
creating individual value validators:
-
Use the ValidatorFactory facade to
create validators. This approach makes it easy to create
type validators that you can use, in conjunction with rule sets,
to validate multiple members of an object instance. This is
generally the recommended approach. You also use this approach to
create validators that use only validation attributes or data
annotations within the classes you want to validate, or only rule
sets defined in configuration. You can resolve an instance of the
ValidatorFactory using a single
line of code. -
Create individual validators
programmatically by calling their constructor. The
constructor parameters allow you to specify most of the properties
you require for the validator. You can then set additional
properties, such as the Tag or the
resource name and type if you want to use a resource file to
provide the message template. You can also build combinations of
validators using this approach to implement complex validation
rules. -
Resolve individual validators through
the Enterprise Library Container. This approach allows
you to obtain a validator instance using dependency injection; for
example, by simply specifying the type of validator you require in
the constructor of a class that you resolve through the container.
If you specify a name when you resolve the instance, this is
interpreted as the name of the rule set for that validator to use
when validating objects.
Note
Previous versions of Enterprise Library used static
facades named Validation
and ValidationFactory (as opposed
to ValidatorFactory
described above) to create validators and perform
validation. While these facades are still available for backwards
compatibility, you should use the approaches described above for
creating validators as you write new code.
Performing Validation and Displaying Validation Errors
To initiate validation, you call the Validate method of your validator. There are
two overloads of this method: one that creates and returns a populated
ValidationResults instance, and one
that accepts an existing ValidationResults instance as a parameter. The
second overload allows you to perform several validation operations,
and collect all of the errors in one ValidationResults instance.
You can check if validation succeeded, or if any validation
errors were detected, by examining the IsValid property of a ValidationResults instance, and displaying
details of any validation errors that occurred. The following code
shows a simple example of how you can display the most
relevant details of each validation error.
// Check if the ValidationResults detected any validation errors. if (results.IsValid) { Console.WriteLine("There were no validation errors."); } else { Console.WriteLine("The following {0} validation errors were detected:", results.Count); // Iterate through the collection of validation results. foreach (ValidationResult item in results) { // Show the target member name and current value. Console.WriteLine("Target:'{0}' Key:'{1}' Tag:'{2}' Message:'{3}'", item.Target, item.Key, item.Tag, item.Message); } }
Alternatively, you can extract more information about the
validation result for each individual validator where an error
occurred. The example application we provide demonstrates how you can
do this.
Understanding Message Template Tokens
One specific and very useful feature of the individual
validators you define in your configuration or attributes is the
capability to include tokens in the message to automatically insert
values of the validator's properties. This applies no matter
how you create your validator—in rule sets defined in
configuration, as validation attributes, or when you create validators
programmatically.
The Message property of a
validator is actually a template, not just a simple text string that
is displayable. When the block adds an individual ValidationResult to the ValidationResults instance for each validation
error it detects, it parses the value of the Message property looking for tokens that it
will replace with the value of specific properties of the validator
that detected the error.
The value injected into the placeholder tokens, and the number
of tokens used, depends on the type of validator—although there are
three tokens that are common to all validators. The token {0} will be replaced by the value of the object
being validated (ensure that you escape this value before you display
or use it in order to guard against injection attacks). The token
{1} will contain the name of the member
that was being validated, if available, and is equivalent to the
Key property of the validator. The
token {2) will contain the value of the
Tag property of the validator.
The remaining tokens depend the on the individual validator
type. For example, in the case of the Contains Characters validator,
the tokens {3} and {4} will contain the characters to check for
and the ContainsCharacters value
(All or Any). In the case of a range validator, such as
the String Length validator, the tokens {3} to {6} will
contain the values and bound types (Inclusive,
Exclusive, or Ignore) for the
lower and upper bounds you specify for the validator. For example, you
may define a String Length validator like this:
[StringLengthValidator(5, RangeBoundaryType.Inclusive, 20, RangeBoundaryType.Inclusive, MessageTemplate = "{1} must be between {3} and {5} characters.")]
If this validator is attached to a property named Description, and the value of this property is
invalid, the ValidationResults instance
will contain the error message Description must
be between 5 and 20 characters.
Other validators use tokens that are appropriate for the type of
validation they perform. The documentation installed with Enterprise
Library lists the tokens for each of the Validation block validators.
You will also see the range of tokens used in the examples that
follow.
|