Using the Enterprise Library Validation Application Block in ASP.NET - Part I

By Alex Homer

This article shows how you can take advantage of the validation features within the Validation Application Block, part of version 3.0 of Enterprise Library, in your ASP.NET applications. The block supports both UI and object validation, and you can combine these approaches using the same rules if you wish. The ability to validate objects is particularly useful when working with instances that may be generated locally, exposed by other tiers of your application, or received from a remote Web Service.

Contents

  • Using the Enterprise Library Validation Application Block in ASP.NET - Part I

Introduction

ASP.NET includes a series of built-in validation controls, integrated with Visual Studio 2005 and Visual Web Developer 2005 Express Edition (VWD), that you can easily incorporate into your Web applications. The validation controls link to existing data entry controls, such as text boxes and list boxes, providing a great client-side user experience while still ensuring that validation also occurs server-side (to protect against spoofing attacks) when the user submits the page.

So, why would you consider using any other type of validation mechanism? The answer depends on what you actually need to validate, where it comes from, and how you want to manage the validation process. Validation within the UI is fine if you are collecting values directly from users, but you may need to do more. For example, you may need to validate object instances that you:

  • Generate in separate tiers or components of your application
  • Retrieve from a cache, a repository, or a third-party data access layer
  • Receive from a Web Service as an object instance or a set of property values
  • Reconstruct from existing values, perhaps populating them by copying properties from a similar object or using values retrieved from a database

The ASP.NET validation controls are of limited use in these situations. In addition, the parameters for the validation (such as the maximum and minimum values, regular expressions, and other data) for each validated control must reside within the control declarations, or you must set them dynamically at runtime from some other stored configuration source (such as the <appSettings> section of Web.config).

An alternative approach is to make use of the wide-ranging and powerful features of the Validation Application Block. This is part of Enterprise Library version 3.0, from the Microsoft patterns & practices group. The Validation Application Block provides a comprehensive series of validation components that you can apply through configuration, or through attributes applied directly to classes, class members, plus UI controls for use in both ASP.NET and Windows Forms applications.

One of the major advantages with this approach is that you can define rule sets within your application configuration file, with each rule set defining the types of validation to undertake and the individual parameters for that validation process. This means that administrators can quickly and easily change the validation rules and parameters without requiring any changes to the existing code - avoiding the risk of code errors, recompilation issues, and application downtime.

You can also create custom validators that validate individual classes or custom types, and integrate these seamlessly with the existing validators. You can even include validation information within your custom classes and types, so that they support self-validation.

In this article, you will see how you can create rule sets and apply them to existing and new instances of objects, and to UI controls in a Web page. For an example of using directly-applied validation attributes within a class, see the article "Using the Policy Injection Application Block in ASP.NET" at http://www.devx.com/dotnet/Article/34517, which demonstrates the use of the Validation Handler with individual Validation Attributes.

The documentation installed with Enterprise Library 3.0 also contains comprehensive details and examples of how you can use attributes to apply validation rules, how to create custom validators, and how to use self-validation. Once you are familiar with the basic process for creating and using rule sets and the validators from the Validation Application Block, you will find it easy to extend the techniques to implement all kinds of custom validation mechanisms.

The Validation Application Block Built-in Validators

The Validation Application Block contains a wide range of validators that you can use to check almost any type of property or value. The built-in validators include:

  • Range validators, such as the generic Range Validator, the Date Time Range Validator, and the String Length Validator. These validators have properties that define the upper and lower bounds, and the bound type (Inclusive, Exclusive, or Ignore) that allow you to specify exactly what value range is valid. If you set a bound type to Ignore, the validator does not check that boundary, so you can use them to specify that valid values are greater than or less than a specific value, as well as between two values.
  • Comparison validators, such as the Property Comparison Validator that checks the value against a specified property of a specified object, and the Relative Date Time Validator that checks if the difference between the value and a specified DateTime is within a valid range.
  • The Not Null Validator, which requires a value to be present.
  • Validators that perform specific tests on string values, such as the Regular Expression Validator, the Contains Characters Validator, and the Type Conversion Validator that checks if a string value can be converted to a specified value type.
  • Validators that check if a value is in a specified set, such as the Domain Validator that checks against a list of values you provide, or the Enum Validator that checks against a specified enumeration.
  • Validators that operate on custom objects, such as the Object Validator that activates validation of an object instance using rules applied to the object, and the Object Collection Validator that does the same for a collection of object instances.
  • Composite validators, such as the And Composite Validator and the Or Composite Validator. These validators allow you to combine other validators by nesting them within this type of validator to create complex validation rules.

The validators have specific properties, depending on the validation process they carry out. However, all of the validators also have some common properties:

  • Tag, which can contain text you use to categorize or filter results, or insert into the validation error message. You can access the Tag value in code when validating rule sets.
  • Negated, which reverses the operation of the validator so that it returns False if the value is valid, and True if not. This is useful when you combine validators using the And Composite Validator and the Or Composite Validator.
  • MessageTemplate, where you specify the validation error message. You can include the placeholders {0}, {1}, and {2} to insert the validated value, the target object member name (if available), and the value of the Tag property of the validator.
  • MessageTemplateResourceName and MessageTemplateResourceType. You can use these properties to retrieve a validation error message string from the application resources assembly. If you create resources for multiple cultures, the validator will automatically retrieve the string for the current culture.

Configuring Validation Rule Sets

To create a rule set for an object, you must first create and compile that object. The example application contains a simple class named CompanyDetails (in the EntLibSampleObject project) that exposes six properties: four of type String, one of type DateTime, and one of type Int32. Open the example solution and view the file EntLibSampleObject.cs to see the class definition.

Once you have a target object class, open the configuration file for your application in one of the two Enterprise Library configuration tools - either the Configuration Console (available from the Start menu), or the Configuration Editor integrated within Visual Studio (right-click on the Web.config or App.config, file in the Solution Explorer window and select Edit Enterprise Library Configuration).

Note: Editing Enterprise Library 3.0 Configuration Files

The default Enterprise Library Configuration Console (opened from your Start menu) will not work with applications that use unsigned versions of the Enterprise Library assemblies located in the Bin folder, as is the case with the examples for this article. Instead, you can use the version of the Configuration Console in the App Blocks\Bin subfolder of your EntLibSrc folder. Run the BuildLibraryAndCopyAssemblies.bat file in the App Blocks subfolder to compile the Enterprise Library source code in your EntLibSrc folder.

Alternatively, use the built-in VS2005 Configuration Editor. The solution file for the example application has the EnterpriseLibraryConfigurationSet property set to EntLib3Src so that the editor will use the unsigned assemblies in your EntLibSrc folder instead of the signed assemblies in the Program Files folder. To change the behavior of the VS 2005 Configuration Editor if you do not have a solution file:

  1. Use the File menu to add a new Web Site to the project so that VS creates a root-level solution node containing the two projects.
  2. Select the solution node and open the Properties window by pressing F4.
  3. Change the EnterpriseLibraryConfigurationSet property to specify the target assembly set you require, and click OK in the warning dialog.
  4. Select Save <solution-name> As from the File menu and save the solution file into the project folder.
  5. Select the project node for the new Web Site project you added, right-click, and select Remove.
  6. Select Save All from the File menu.
  7. Use the saved solution file (.sln) to open the project in future.

Specifying the Target Object Type

In the configuration editor, right click on the application node (the node immediately below the root Enterprise Library Configuration node) and select New, then click Validation Application Block to add the Validation Application Block to your application. Then right-click on the new Validation Application Block node, select New, and click Type. In the Type Selector dialog, click the Load an assembly... button and navigate to the folder containing your target object. Click Open to load this assembly.

The Type Selector dialog now shows a tree view of all the assemblies containing classes that inherit from System.Object, sorted alphabetically. Find your target assembly in the list (collapse nodes in the tree to make it easier) and select the target class to which you want to attach a rule set (see Figure 1).

Selecting the target class
Figure 1 - Selecting the target class for applying a rule set in the Enterprise Library Configuration Editor

Click OK, and the class appears in the configuration under the Validation Application Block node. Now you are ready to create the rule set.

Creating a Rule Set and Adding Validators

Right-click on the new target object node in the configuration editor, select New, and click Rule Set. Change the name of the rule set as required - you will use the name in your code so you should specify a name that will help you to read and debug your code, especially if you define more than one rule set.

The next stage is to select the members of the target object that you want to validate. Right-click on the new rule set node, select New, and click Choose Members to display a dialog containing all the public members of the target object (see Figure 2). Select the required members and click OK to close the dialog and add these members to the rule set.

Selecting the members of the target class
Figure 2 - Selecting the members of the target class to which you want to apply validators

Alternatively, to add specific members, right-click on the rule set node, select New, and click Field, Method, or Property. This adds a new node to the rule set. Select the new node and change the name to that of the target object's field, method, or property.

You now have a hierarchy that contains the list of members to which you will add validators. For each target object member, right-click on it, select New, and click the type of validator you want to add. As you add each one, use the Properties window in Visual Studio 2005, or the properties list in the right-hand pane of the Configuration Console, to set the properties you require for each validator.

For example, the CompanyAddress property of the CompanyDetails object in the example application has a String Length Validator attached with the following properties set:

Property Setting
LowerBound 5
LowerBoundType Inclusive
Negated False
Tag CompanyAddressValidator
UpperBound 100
UpperBoundType Inclusive
MessageTemplate Company address must be between 5 and 100 characters

Figure 3 shows the completed configuration of the example application. You can see the six properties of the target object class, and the validator specified for each one. The Self node, which the configuration tool adds automatically, allows you to specify validators that will operate on objects that carry the SelfValidation attribute. For more details of self validation, see the topic "Using Self Validation" in the "Key Scenarios" section of the Enterprise Library Validation Application Block documentation.

The configuration of validators in the example application.
Figure 3 - The configuration of validators in the example application. The CompanyDetails class has a rule set named ExampleRuleSet that contains the appropriate validator for each property, depending on the value type

Using Composite Validators

The example application implements a simple scenario where there is only one validator on each property of the target class. However, if you need to perform more complex validation, you can use a composite validator to created nested validator groups that implement AND and OR logic.

For example, you can add an And Composite Validator to a property, and then right-click on this validator, select New, and select other validators to place within this AND group. You might choose to use a Not Null Validator and a Type Conversion Validator, which must both return True for the property value to be considered valid.

You can add more than two validators to a composite validator, nest composite validators within other composite validators, and use the Negated property of any validator to reverse its behaviour. It is difficult to conceive of a validation requirement that you cannot meet using these capabilities.

Using Validation Rule Sets in ASP.NET

The example application for this article displays textboxes for the six properties of the target object. These are pre-filled with valid values to save you typing then in. If you open the application and click the Create a company using these values... button, without changing any of the values in the text boxes values or the other settings, the code creates an instance of the target class with valid values, performs validation on the object, and displays the property values and the validation result in the page (see Figure 4).

The example application creates an instance of the target object
Figure 4 - The example application creates an instance of the target object, validates its properties, and displays the results

If you now edit the values in the text boxes so that they are outside the range of valid values, and click the Create a company using these values... button again, the page displays a list of errors it encounters when validating the new object instance (see Figure 5). You can see in this case that the CompanyName, CompanyPostalCode, and EmployeeCount properties have invalid values.

The result of validating an object with invalid property values
Figure 5 - The result of validating an object with invalid property values

For each invalid property value, the page displays the contents of the MessageTemplate for the validator, the name of the target property, the value of the Tag property of the validator, and the type name of the target object.

Validating Object Instances

The code-behind file for the example application's Default.aspx page starts by importing the namespaces containing the classes the code uses. You can the Validation Application Block assemblies here, and the example target object. The application also uses a Web Service, as you will see shortly, and imports this namespace as well:

using System;
using System.Web.UI;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Integration.AspNet;
using EntLibSamples; // defines the sample CompanyDetails class
using SampleService; // returns valid and invalid CompanyDetails instances

The handler for the Create a company using these values... button starts by calling a simple routine that creates an instance of the example target object and sets the properties using the values in the text boxes in the page:

private void CreateLocalCompanyObject()
{
  // create sample object instance and set properties
  EntLibSamples.CompanyDetails companyObject
    = new EntLibSamples.CompanyDetails();
  companyObject.CompanyName = txtName.Text;
  companyObject.CompanyAddress = txtAddress.Text;
  companyObject.CompanyCity = txtCity.Text;
  companyObject.CompanyPostalCode = txtPostalCode.Text;
  companyObject.EmployeeCount = Int32.Parse(txtEmployees.Text);
  companyObject.LastReportDate = DateTime.Parse(txtReportDate.Text);

  // display and validate property values
  DisplayAndValidateSampleObject(companyObject);
}

After populating the object, the code above calls another routine named DisplayAndValidateSampleObject that begins by creating a StringBuilder containing the property values for display in the page:

private void DisplayAndValidateSampleObject(
                  EntLibSamples.CompanyDetails targetObject)
{
  // read properties for display in the page
  StringBuilder builder
    = new StringBuilder("<b>New Object Properties</b>:<br />");
  builder.Append(String.Format("- Name: <b>{0}</b><br />",
                               targetObject.CompanyName));
  builder.Append(String.Format("- Address: <b>{0}</b><br />",
                               targetObject.CompanyAddress));
  builder.Append(String.Format("- City: <b>{0}</b><br />",
                               targetObject.CompanyCity));
  builder.Append(String.Format("- Postal Code: <b>{0}</b><br />",
                               targetObject.CompanyPostalCode));
  builder.Append(String.Format("- Employees: <b>{0}</b><br />",
                               targetObject.EmployeeCount.ToString()));
  builder.Append(String.Format("- Last Report: <b>{0}</b><p />",
                               targetObject.LastReportDate.ToString()));
  ...

The Validate Method

Next is the validation process. Unlike the ASP.NET UI validation controls, which react to an event in the ASP.NET page cycle to perform validation, the Validation Application Block validators must be explicitly executed by calling the static Validate method of the block. This method takes as parameters the reference to the target object to validate and the name of the rule set containing the validation rules to apply to the target object:

// in C#:
ValidationResults results;
results = Validation.Validate(targetObject, "RulesetName");

' in Visual Basic.NET:
Dim results As ValidationResults
results = Validation.Validate(targetObject, "RulesetName")

If you have specified a default rule set for the target object (by setting the DefaultRule property of the target object node in the configuration editor), you can omit the second parameter:

// in C#:
ValidationResults results;
results = Validation.Validate(targetObject);

' in Visual Basic.NET:
Dim results As ValidationResults
results = Validation.Validate(targetObject)

The Validate method also has a generics-based override that takes the type of the target object. You can use this override if you want to indicate the target class type of an inheriting object type:

// in C#:
ValidationResults results;
results = Validation.Validate<targetObjectType>(targetObject, "Ruleset");

' in Visual Basic.NET:
Dim results As ValidationResults
results = Validation.Validate(Of targetObjectType)(targetObject, "Ruleset")

Note: You can instead use the static CreateValidator method of the block to create a Validator instance for a specified class instance, and then call the Validate method on that Validator instance. This approach allows you to specify whether the validation process should uses rules that are defined in the configuration, or declared as attributes on classes and class members.

Displaying the Validation Results

The Validate method returns an instance of the ValidationResults class, which is a collection containing a ValidationResult instance for each validation failure. The ValidationResult class exposes properties that allow you to obtain the value of the Key (the member name if available), the Message describing the validation error, the value of the validator Tag property, the type name of the Target object, and the name of the Validator. There is also the NestedValidationResults property, which exposes a ValidationResults collection containing the validation errors for any nested validators (when using a composite validator).

The example application calls the Validate method, and then checks if there were any validation errors by examining the IsValid property of the returned ValidationResults collection. If there are errors, the code iterates through the collection adding the values of the Key, Tag, and Target properties of each ValidationResults instance to the StringBuilder. If there are no errors, it adds a suitable message to the StringBuilder instead. Finally, the code displays the contents of the StringBuilder in a Label control on the page:

  ...
  // validate the property values using the configured rule set
  ValidationResults results;
  results = Validation.Validate<EntLibSamples.CompanyDetails>(
                                targetObject, "ExampleRuleSet");

  // get validation results
  if (!results.IsValid)
  {
    builder.Append("<b>Validation Errors:</b>:<br />");
    foreach (ValidationResult result in results)
    {
      builder.Append(String.Format("- <b>{0}</b><br />", result.Message));
      builder.Append(String.Format("&nbsp; (Key: {0}, ",
                                   result.Key.ToString()));
      builder.Append(String.Format("Tag: {0}, ", result.Tag));
      builder.Append(String.Format("Target: {0})<br />",
                                   result.Target.ToString()));
    }
  }
  else
  {
    builder.Append("All object property values are valid.");
  }

  // display results in Label control
  lblResult.Text = builder.ToString();
}

About the Author

Alex Homer is a freelance developer and writer, currently sending most of his time working with Wrox Press Limited in the UK. Alex's own company, Stonebroom Software, has been running - on and off and with a couple of name changes - for some fifteen years while he held down a 'day-job' as well. He started writing system utilities in assembler (machine code) which were sold through a small distributor in Blackpool, the UK's 'silicon beach' of home computing in the early eighties. Since then, development has moved through Pascal in MS-DOS, Delphi and Visual Basic in Windows, and now to the Internet in general. Having worked in the Glass and Glazing industry for some years, Alex also develops vertical market software aimed at making the specifier's and estimator's job easier. They still think Windows are things you lean out of.



Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date