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

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

Validating Objects from Other Sources

To demonstrate how useful the Validation Application Block is, and how you can use a rule set to validate object instances wherever they originate from, the example application contains a simple Web Service that returns populated instances of a class compatible with the CompanyDetails target class.

The Example Web Service

The Web Service project, named SampleWebService, uses the following code to expose two Web Methods. The GetValidCompanyInstance method returns an object with valid property values, and the GetInvalidCompanyInstance method returns an instance with invalid values for all of the properties:

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using EntLibSamples;

[WebService(Namespace = "http://www.daveandal.net/articlesamples/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class CustomerService : System.Web.Services.WebService
{

  [WebMethod]
  public EntLibSamples.CompanyDetails GetValidCompanyInstance()
  {
    // create sample object instance and set properties
    EntLibSamples.CompanyDetails companyObject
      = new EntLibSamples.CompanyDetails();
    companyObject.CompanyName = "FooBar Trading Company";
    companyObject.CompanyAddress = "123, The Industrial Estate";
    companyObject.CompanyCity = "Manchester";
    companyObject.CompanyPostalCode = "12345-1234";
    companyObject.EmployeeCount = 12;
    companyObject.LastReportDate = new DateTime(2007, 03, 03);
    return companyObject;
  }

  [WebMethod]
  public EntLibSamples.CompanyDetails GetInvalidCompanyInstance()
  {
    // create sample object instance and set properties
    EntLibSamples.CompanyDetails companyObject
      = new EntLibSamples.CompanyDetails();
    companyObject.CompanyName = "Foo";
    companyObject.CompanyAddress = "Bar";
    companyObject.CompanyCity = "A really long city name that "
                              + "exceeds the validation limit";
    companyObject.CompanyPostalCode = "England";
    companyObject.EmployeeCount = 0;
    companyObject.LastReportDate = new DateTime(2002, 10, 10);
    return companyObject;
  }
}

You can see that the Web Service references the EntLibSamples namespace, and creates instances of the example CompanyDetails class from that namespace. However, as you will see shortly, you still need to convert the object exposed by the Web Service to the correct type for validation.

Validating Objects from the Example Web Service

The code-behind file for the Default.aspx page in the main Web site contains code to access the example Web Service to obtain instances of the target class that it can validate and display. However, although the Web Service returns an object compatible with the CompanyDetails class defined in the configuration, it is not directly convertible. Therefore, the code contains a simple routine that creates a new instance of the local EntLibSamples.CompanyDetails class, and then copies to it the property values from the SampleService.CompanyDetails instance returned by the Web Service:

private EntLibSamples.CompanyDetails ConvertServiceObject(
                      SampleService.CompanyDetails serviceObject)
{
  // generate local CompanyDetails object from the values
  EntLibSamples.CompanyDetails companyObject
    = new EntLibSamples.CompanyDetails();
  companyObject.CompanyName = serviceObject.CompanyName;
  companyObject.CompanyAddress = serviceObject.CompanyAddress;
  companyObject.CompanyCity = serviceObject.CompanyCity;
  companyObject.CompanyPostalCode = serviceObject.CompanyPostalCode;
  companyObject.EmployeeCount = serviceObject.EmployeeCount;
  companyObject.LastReportDate = serviceObject.LastReportDate;
  return companyObject;
}

The handlers for the Create a Valid Company using a Web Service and Create an Invalid Company using a Web Service buttons start by creating a reference to the Web Service, and then call the relevant method to get the new object instance. Then they can convert the object to the relevant type using the routine just described, and pass it to the DisplayAndValidateSampleObject method (described earlier) for validation and display. For example, this is the code in the Create a Valid Company... button handler:

// get valid sample object instance from Web Service
CustomerService service = new CustomerService();
SampleService.CompanyDetails serviceObject
    = service.GetValidCompanyInstance();

// generate local CompanyDetails object from the values
EntLibSamples.CompanyDetails companyObject
    = ConvertServiceObject(serviceObject);

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

Figures 6 and 7 show the results when you click the Create a Valid Company using a Web Service and Create an Invalid Company using a Web Service buttons in the example application.


Figure 6 - The result of validating an object obtained from a remote Web Service with valid property values when you click the "Create a Valid Company using a Web Service" button


Figure 7 - The result of validating an object obtained from a remote Web Service with invalid property values when you click the "Create an Invalid Company using a Web Service" button

UI Validation Integration in ASP.NET

The Validation Application Block contains UI validation integration features for both Windows Forms and ASP.NET applications. Of course, both of these environments already include built-in UI validation controls and features; however the capability for integrating validation across both the UI and object instances within an application is extremely useful. For example, as you will see in the example application, you can use a common rule set for validation of both UI and objects.

The example application contains a drop-down list where you can turn on and off UI validation for controls in the page. If you set this option to enabled, and then create and validate an object instance, you will see that the page displays the error messages next to each text box, and does not actually create a new object for validation (see Figure 8). Instead, it displays a message indicating that validation errors occurred.


Figure 8 - The result of validating the proposed values for the properties of the sample object when ASP.NET integration is enabled

The PropertyProxyValidator Control

ASP.NET integration uses a class named PropertyProxyValidator, which implements a control that you can use within an ASP.NET Web page to perform UI validation. This control inherits from the ASP.NET validation control base class named BaseValidator, and is therefore effectively an ASP.NET validation control.

The BaseValidator class exposes properties such as ControlToValidate, Display (None, Static, Dynamic), EnableClientScript, Enabled, IsValid, SetFocusOnError, and ValidationGroup. However, many of these are set within the PropertyProxyValidator class, although - as you will see - you can also set them yourself in code, or with attributes within the control declaration on an .aspx page.

The PropertyProxyValidator class also exposes the Validate method, which you can use to initiate validation of specific validators if required. However, all the instances of the PropertyProxyValidator class you place in a page integrate with the ASP.NET validation system, and so you can cause validation by calling the Validate method of the Page class, and check the result using the IsValid property of the Page class.

Note: You must call the Page.Validate method, or the Validate method of individual validation controls, to validate submitted values when using the PropertyProxyValidator class. This does not occur automatically.

To use the PropertyProxyValidator class, you simply add instances to the ASP.NET page, either by declaring them within the .aspx file or by generating instances dynamically at runtime and adding them to the Controls collection of the Page object or another container control. The process is identical to adding ASP.NET built-in validation controls such as the RequiredFieldValidator or any other ASP.NET control) to a page.

The only real differences when working with the Validation Application Block compared to the ASP.NET validation controls are:

  • You must include an @Register directive in the ASP.NET page to register the integration assembly that contains the PropertyProxyValidator control:

    <%@ Register Assembly="Microsoft.Practices.EnterpriseLibrary
                          .Validation.Integration.AspNet"
                 Namespace="Microsoft.Practices.EnterpriseLibrary
                           .Validation.Integration.AspNet"
                 TagPrefix="EntLibValidators" %>

  • You use only one type of validation control, the PropertyProxyValidator control, for all validation operations. The actual operation and parameters appear in the configuration file or in attributes applied to the target object class and its members. You should have a target object class defined that supports validation through configuration or attributes.

  • You specify the name of the rule set, the type name of the target object, and the target object member (method or property name) in the PropertyProxyValidator control declaration. For example:

    <EntLibValidators:PropertyProxyValidator ID="CompanyNameValidator"
        runat="server" ControlToValidate="txtName"
        PropertyName="CompanyName" RulesetName="ExampleRuleSet"
        SourceTypeName="EntLibSamples.CompanyDetails" />

  • You may need to convert the values obtained from the input control to a suitable type if the .NET default type conversion mechanism cannot automatically convert the type. Create a handler for the ValueConvert event of the validation control that accepts a ValueConvertEventArgs instance, convert the object passed as the ValueToConvert property of this instance to the appropriate type, then return it as the ConvertedValue property. If conversion is not valid, set the ConversionErrorMessage property to a suitable error message. However, for most simple value types, this is not required.

  • The PropertyProxyValidator control does not appear in the Visual Studio 2005 Toolbox by default. However, you can add it to the General section of the Toolbox by opening the Choose Items dialog, browsing to the Microsoft.Practices.EnterpriseLibrary.Validation.Integration.AspNet.xml assembly, and placing a tick next to PropertyProxyValidator in the list of Toolbox components. Figure 9 shows how Visual Studio 2005 displays the PropertyProxyValidator control in Design view.


Figure 9 - The Default.aspx page of the example application in Design view showing the PropertyProxyValidator controls

Implementing UI Validation in the Example Application

The first step in adding Validation Block integration with ASP.NET is to declare the PropertyProxyValidator controls for each UI input control. This is simply a matter of dragging the control from the Toolbox (if you have installed it there) onto the page in Design view, or typing and then pasting and copying the declaration in Source view. Also remember that you must add the appropriate @Register directive to the page as well, as described in the previous section of this article.

For each validated UI input control, specify that input control's ID property as the ControlToValidate property of the PropertyProxyValidator control. Also set the RulesetName, SourceTypeName, and PropertyName properties to the appropriate values based on your application configuration. You can view the Default.aspx page in the example application to see the final result.

Validating the UI Control Values

To validate the UI control values, add code to the handler for the button or other control that submits the page. The example application checks the Page.IsValid property, and - if it True - creates an instance of the target object and displays its property values in the page. A separate routine named CreateLocalCompanyObject performs the task of applying the validated UI values to a new instance of the target object, and displaying its properties in the page:

// force validators to check control values
Page.Validate();
if (Page.IsValid)
{
  // create sample object instance and set properties
  CreateLocalCompanyObject();
}
else
{
  lblResult.Text = "Validation errors encountered by ASP.NET "
                 + "Integration Validators<p />";
}

You saw the CreateLocalCompanyObject routine used (and described) in the earlier section of this article "Validating Object Instances". As well as creating the new object instance and displaying the property values, this routine performs object-level validation by calling the static Validate method of the Validation Application Block.

Note: It is always a good idea to repeat on the server any UI validation you carry out before using posted values in your application. This protects against spoofing attacks; and against issues that may arise is client browsers do not fully support or correctly process client-side script. However, unlike the ASP.NET validation controls, the PropertyProxyValidator controls only perform validation server-side, and not through client-side script.

Accessing PropertyProxyValidator Controls in Code

One other features of the example application is the ability (as you have seen) to enable and disable UI integrated validation. The code to achieve this demonstrates a useful technique that you can take advantage of to change the behaviour of some or all instances of the PropertyProxyValidator control in your pages.

The Default.aspx page contains a drop-down list that defines two values: "disabled" (value = False) and "enabled" (value = True):

<asp:DropDownList runat="server" ID="lstEnableIntegration">
  <asp:ListItem Text="disabled" Value="false" />
  <asp:ListItem Text="enabled" Value="true" />
</asp:DropDownList>

The example application also contains code in the handler that executes in response to the Page.Load event. This code iterates through all the instances of PropertyProxyValidator controls on the page, setting the Enabled property to that specified in the drop-down list control. Notice that it accesses each validation control using the IValidator interface (from the System.Web.UI namespace), which means that the code will work in a page that contains built-in ASP.NET validation controls as well as PropertyProxyValidator controls:

protected void Page_Load(Object sender, System.EventArgs e)
{
  // set the Enabled property for every EntLib Validator control
  foreach (IValidator validatorControl in Page.GetValidators(null))
  {
    if (validatorControl is PropertyProxyValidator)
    {
      PropertyProxyValidator ctrl
        = (validatorControl as PropertyProxyValidator);
      ctrl.Enabled = Boolean.Parse(lstEnableIntegration.SelectedValue);
    }
  }
}

Note: If you have defined validation groups for the validators in your page, you can select just the validation controls in that group using the single parameter of the Page.GetValidators method. See the ASP.NET documentation for details of using validation groups in ASP.NET.

The code checks if each validator it finds is of type PropertyProxyValidator, and - if it is - casts the reference to the PropertyProxyValidator type so that it can set the Enabled property to the value selected in the drop-down list. You can use this technique to set the properties of any type of validation control.

The Visual Basic.NET equivalent of the Page.Load routine, showing the different syntax for converting the validator control reference, is:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
  ' set the Enabled property for every EntLib Validator control
  For Each validatorControl As IValidator In Page.GetValidators(Nothing)
    If TypeOf validatorControl Is PropertyProxyValidator Then
      CType(validatorControl, PropertyProxyValidator).Enabled _
        = Boolean.Parse(lstEnableIntegration.SelectedValue)
    End If
  Next
End Sub

One final twist to the code in the example application is that, when UI validation integration is enabled, it only creates the target object instance and performs server-side validation of the property values if the UI validation does not detect any validation errors. The actual code used in the example application is:

// check if user has turned on ASP.NET client-side integration
if (lstEnableIntegration.SelectedValue == "true")
{
  // force validators to check control values
  Page.Validate();
  if (Page.IsValid)
  {
    // create sample object instance and set properties
    CreateLocalCompanyObject();
  }
  else
  {
    lblResult.Text = "Validation errors encountered by ASP.NET "
                   + "Integration Validators<p />";
  }
}
else
{
  CreateLocalCompanyObject();
}

Summary

This article discussed how you can take advantage of the Enterprise Library Validation Application Block in ASP.NET applications, concentrating on the use of rule sets that allow validation across the UI and object instances within the application tiers (and, if required, in Windows Forms applications as well).

While ASP.NET provides a fully-featured set of UI validation controls, these do not always fulfil the requirements of enterprise-level applications. The Validation Application Block supports a wider range of validators, has features to allow composition and negation of validators, and supports validation using configuration rules as well as attributes applied directly to classes and class members.

In the example application that accompanies this article, you can see how easy it is to use the Validation Application Block and a rule set to validate local objects, object instances generated from calls to a remote Web Service, and UI input control values.

You can also combine the Validation Application Block validators with the ASP.NET built-in validators if required. The PropertyProxyValidator control that supports ASP.NET integration is itself a descendant of the ASP.NET validator base class, and so behaves and can be handled in the same way as the ASP.NET validation controls.

Having seen the capabilities it provides, you may wish to consider using the Validation Application Block to extend the validation capabilities of your code as you build applications that are ever more complex, and more highly distributed in nature.

Download the Source Code

You can download the source code presented in this article in zip file format from here: 070607.zip.

posted on 2007-06-20 11:21  心悦  阅读(1430)  评论(0编辑  收藏  举报