Understanding ASP.NET Validation Library

Introduction

ASP.NET provides different options for validation at the client side. Each of the validation controls emits client side JavaScript behind the scenes for data validation. In the earlier versions of ASP.NET, the client side library was open for modification. Starting with ASP.NET 2.0, these functions are in the source file WebUIValidation.js which is included as an embedded resource within the System.Web assembly. This article looks at these internal functions and takes a deep dive approach to understand how they work with web controls during the page validation process.

How does Validation actually work?

In order to demonstrate the ASP.NET validation process, let us create a simple example using these quick steps to create a web application called "SimpleValidationTest":

  • Create a new WebSite in VS 2005.
  • Drag and drop a textbox (TextBox1), a required field validator (RequiredFieldValidator1), and a button (Button1) on the form.
  • Add a validation summary (ValidationSummary1) control.

When an ASP.NET server side validation control is used, during the rendering phase it embeds in the HTML output some client side JavaScript code used to perform validation. All the ASP.NET validation controls inherit from BaseValidator and the rendering of common functions happens within this class. When using any built in validation controls, these functions are always plugged into the rendered HTML source. The rendered functions are mentioned below along with a brief description.

Modified form tag: The first thing to note when using ASP.NET validation is that additional attributes are added to the form element. It is modified to execute the below JavaScript code for validation purposes.

  1. onsubmit="javascript:return WebForm_OnSubmit();"  

The onsubmit attribute is added during the rendering phase by the BaseValidator class. Inside the OnPreRender method, the common initialization tasks are invoked through the RegisterValidatorCommonScript method. One of the steps is to render the submit script shown above, which is rendered via the Page.ClientScript.RegisterOnSubmitStatement method.

Common JavaScript validation functions used across all validators are shown in listings 1 and 2 which can be seen in the rendered HTML source.

Listing 1: The WebForm_OnSubmit function

  1. function WebForm_OnSubmit() {  
  2.    if (typeof(ValidatorOnSubmit) == "function" && ValidatorOnSubmit() == false)   
  3.       return false;  
  4.   
  5.    return true;  
  6. }  

The function WebForm_OnSubmit in listing 1, which is invoked when the form is posted, does not submit the form if the page is not valid. This condition is determined by the ValidatorOnSubmit function, shown in listing 2.

Listing 2: The ValidatorOnSubmit function

  1. var Page_ValidationActive = false;  
  2. if (typeof(ValidatorOnLoad) == "function") {  
  3.     ValidatorOnLoad();  
  4. }  
  5.   
  6. function ValidatorOnSubmit() {  
  7.     if (Page_ValidationActive) {  
  8.         return ValidatorCommonOnSubmit();  
  9.     }  
  10.     else {  
  11.         return true;  
  12.     }  
  13. }  

The ValidatorOnLoad function enumerates through the validators collection on the page to initialize each of them, and sets Page_ValidationActive to true. In turn, the ValidatorOnSubmit function is executed since Page_ValidationActive is true. By default, Page_BlockSubmit is set to false and ValidatorCommonOnSubmit returns !Page_BlockSubmit. During client side Page validation, Page_BlockSubmit is set to !Page_IsValid. Thus, an invalid page turns Page_IsValid to false, setting the return value of ValidatorCommonOnScript to false. The page validation process is explained in more depth in the section entitled "Page validation in depth".

The JavaScript snippet shown in listing 3 is specific to the particular validators (RequiredFieldValidator1 and ValidationSummary1) used in the page.

Listing 3: Validator-specific code

  1. var Page_ValidationSummaries =  new   
  2.    Array(document.getElementById("ValidationSummary1"));  
  3. var Page_Validators =  new Array(document.getElementById("RequiredFieldValidator1"));  
  4.   
  5. var RequiredFieldValidator1 = document.all ? document.all["RequiredFieldValidator1"]   
  6.                                  : document.getElementById("RequiredFieldValidator1");  
  7.   
  8. RequiredFieldValidator1.controltovalidate = "TextBox1";  
  9. RequiredFieldValidator1.errormessage = "RequiredFieldValidator";  
  10. RequiredFieldValidator1.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";  
  11. RequiredFieldValidator1.initialvalue = "";  

The above code snippet shows that the validator names are added to the Page_Validators collection and that the validation summary control names are added to the Page_ValidationSummaries collection. The main attributes of the validator - namely controltovalidate, errormessage, evaluationfunction and initialvalue are initialized. The value of the evaluationfunction property is determined by the type of the server side validator. The possible values are shown in the following table.

Table 1: Possible values for evaluationfunction rendered at client side

Validator type evaluationfunction
Required Field Validator RequiredFieldValidatorEvaluateIsValid
Range Validator RangeValidatorEvaluateIsValid
Custom Validator CustomValidatorEvaluateIsValid
Compare Validator CompareValidatorEvaluateIsValid

Peeking into the .NET validation libraries

The validation functions listed above can be examined into much more detail if we can peek into WebUIValidation.js source file. There are different ways of achieving this and we are going to show a couple of approaches. The first approach is to peek into the System.Web.UI.WebControls assembly within the embedded resources. We do this with the help of the Reflector tool which uses .NET Reflection to generate the source code of any managed assembly. By opening .NET Reflector and navigating to System.Web, the JavaScript file WebUIValidation.js is found - located under the Resources folder. The second approach is to look at the source while debugging the code in the Visual Studio 2005 IDE. These steps would enable us to set breakpoints within the library and trace the code flow.

  • Open the web application created earlier using Visual Studio 2005 (SimpleValidationTest example). Set the preferred default browser to Internet Explorer .This can be done by right clicking on the Default.aspx page and then clicking on Microsoft Internet Explorer in the browser window; and choosing the "Set as Default" option. Click on Debug->Start debugging or simply press F5 to run the application. Make sure that debugging is enabled in Internet Explorer by checking the Internet Options->Advanced tab under the Tools menu. The check box for "Disable script debugging" must be unchecked for enabling client side debugging.
  • In the Visual Studio 2005 IDE, open the Script Explorer window located under Debug->Windows or under View->Other Windows on the menu. Alternatively, the shortcut Ctrl+Alt+N can be used to show the scripts being used for debugging. Inside the Script Exlorer window, all the JavaScript resources used in the application are displayed. Some of them are injected on the page by the ASP.NET 2.0 framework and others are user defined JavaScript functions. All the embedded resources such as images and scripts are rendered via the inbuilt HTTP handler WebResource.axd. The JavaScript file of our interest starts with the following line of code: var Page_ValidationVer = "125";
  • Once the JavaScript file is opened, all the functions used internally by ASP.NET can be seen and break points can be placed to carry on the normal debugging process.

Page Validation in depth

Earlier, we noted that Page_IsValid determines whether a given page is valid or not. But which function sets this value and how is the function invoked? Using our sample example, we determine the answer to this question by inspecting the HTML rendered by the button control. By default, for every button control, the following attribute is added:

Listing 4: Attribute added to every button controls

  1. onclick="javascript:WebForm_DoPostBackWithOptions(new   
  2.    WebForm_PostBackOptions"Button1", "", true, "", "", false, false))"  

The onclick attribute, along with the script, is added inside the AddAttributesToRender method of the Button control. The WebForm_DoPostBackWithOptions function can be examined in the rendered web resource JavaScript file within Visual Studio 2005, as explained in the above section. This function is in the resource file named WebForms.js. The function takes an argument of type WebForm_PostBackOptions. This function is also responsible for invoking the Page_ClientValidate function, which sets the value of the Page_IsValid member. The complete validation process triggered by the click of a button process can be summarized in the workflow below.

  • Button is clicked
  • function in listing 7 invoked
  • function in listing 5 invoked
  • Page_IsValid is set
  • form is submitted
  • onSubmit event is raised
  • return WebForm_OnSubmit
  • return ValidatorOnSubmit
  • return ValidatorCommonOnSubmit
  • return !Page_BlockSubmit
  • return !(!Page_IsValid)

The above workflow returns true if the page is valid, which in turn submits the form. It returns false if the page is invalid, preventing the form from being submitted. In the latter case, the form displays the error messages under the validation summary control, due to the functions ValidatorUpdateIsValid and ValidationSummaryOnSubmit as shown in the first function reported in Listing 5.

These functions (Page_ClientValidate and WebForm_DoPostBackWithOptions), along with the definition of WebForm_PostBackOptions as seen on Visual Studio 2005, are shown in listings 5, 6, and 7.

Listing 5: The Page_ClientValidate function

  1. function Page_ClientValidate(validationGroup) {  
  2.     Page_InvalidControlToBeFocused = null;  
  3.     if (typeof(Page_Validators) == "undefined") {  
  4.         return true;  
  5.     }  
  6.     var i;  
  7.     for (i = 0; i < Page_Validators.length; i++) {  
  8.         ValidatorValidate(Page_Validators[i], validationGroup, null);  
  9.     }  
  10.     ValidatorUpdateIsValid();  
  11.     ValidationSummaryOnSubmit(validationGroup);  
  12.     Page_BlockSubmit = !Page_IsValid;  
  13.     return Page_IsValid;  
  14. }  

Listing 6: The WebForm_PostBackOptions function

  1. function WebForm_PostBackOptions(eventTarget, eventArgument, validation, validationGroup, actionUrl, trackFocus, clientSubmit) {  
  2.     this.eventTarget = eventTarget;  
  3.     this.eventArgument = eventArgument;  
  4.     this.validation = validation;  
  5.     this.validationGroup = validationGroup;  
  6.     this.actionUrl = actionUrl;  
  7.     this.trackFocus = trackFocus;  
  8.     this.clientSubmit = clientSubmit;  
  9. }  

Listing 7: The WebForm_DoPostBackWithOptions function

  1. function WebForm_DoPostBackWithOptions(options) {  
  2.     var validationResult = true;  
  3.     if (options.validation) {  
  4.         if (typeof(Page_ClientValidate) == 'function') {  
  5.             validationResult = Page_ClientValidate(options.validationGroup);  
  6.         }  
  7.     }  
  8.     if (validationResult) {  
  9.         if ((typeof(options.actionUrl) != "undefined") &&   
  10.                            (options.actionUrl != null) &&   
  11.                            (options.actionUrl.length > 0))   
  12.         {  
  13.             theForm.action = options.actionUrl;  
  14.         }  
  15.         if (options.trackFocus) {  
  16.             var lastFocus = theForm.elements["__LASTFOCUS"];  
  17.             if ((typeof(lastFocus) != "undefined") && (lastFocus != null)) {  
  18.                 if (typeof(document.activeElement) == "undefined") {  
  19.                     lastFocus.value = options.eventTarget;  
  20.                 }  
  21.                 else {  
  22.                     var active = document.activeElement;  
  23.                     if ((typeof(active) != "undefined") && (active != null)) {  
  24.                         if ((typeof(active.id) != "undefined") &&   
  25.                                            (active.id != null) &&   
  26.                                            (active.id.length > 0))   
  27.                         {  
  28.                             lastFocus.value = active.id;  
  29.                         }  
  30.                         else if (typeof(active.name) != "undefined") {  
  31.                             lastFocus.value = active.name;  
  32.                         }  
  33.                     }  
  34.                 }  
  35.             }  
  36.         }  
  37.     }  
  38.     if (options.clientSubmit) {  
  39.         __doPostBack(options.eventTarget, options.eventArgument);  
  40.     }  
  41. }  

Using built-in validation routines in user code

In the previous sections, we looked at the internals of the page validation process. In the following example, we are going to show a sample ASP.NET page where validation is turned on or off depending on a condition. Let us add another TextBox and custom validator to our sample application. This validation function determines whether the required field validator is enabled or not. The validateTextBox1 function takes in two arguments, src and args. When the value entered in TextBox2 is true, RequiredFieldValidator1 is programmatically disabled. This behavior is achieved by leveraging the built-in ValidatorEnable function, which takes in two arguments, the name of the validator and a Boolean flag to enable/disable it. The errormessage attribute of the custom validator is dynamically changed within the code, depending on the user entry. The form is prevented from being submitted by setting args.IsValid to false. The complete source code is shown below.

Listing 8: Source code for the ASP.NET page

  1. <html xmlns="http://www.w3.org/1999/xhtml" >  
  2. <head runat="server">  
  3.     <title>Understanding .NET Validation</title>  
  4. <script type="text/javascript">  
  5. function validateTextBox1(src, args)  
  6. {  
  7.     if (args.Value == "true")  
  8.     {  
  9.         ValidatorEnable(RequiredFieldValidator1, false);  
  10.         src.errormessage = "TextBox1 required field validator is disabled";       
  11.     }  
  12.     else  
  13.     {  
  14.         ValidatorEnable(RequiredFieldValidator1, true);  
  15.         src.errormessage = "Enter true, not '"+args.Value+"' to disable TextBox1 required field validator";  
  16.     }  
  17.      args.IsValid = false;     
  18. }  
  19. </script>  
  20. </head>  
  21. <body>  
  22.     <form id="form1" runat="server">  
  23.     <div>  
  24.     TextBox 1: <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>  
  25.     <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server"    
  26.           Text="*" ControlToValidate="TextBox1"  
  27.           Display="Dynamic"    
  28.           ErrorMessage="TextBox1 is required"></asp:RequiredFieldValidator>  
  29.        <br />  
  30.        Disable required field for TextBox1?      
  31.     <asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>  
  32.     <asp:CustomValidator ID="CustomValidator1" runat="server"   
  33.           Text="*" ControlToValidate="TextBox2" Display="Dynamic"  
  34.           ErrorMessage="CustomValidator"   
  35.           ClientValidationFunction="validateTextBox1"   
  36.           ValidateEmptyText="True"></asp:CustomValidator>  
  37.     <asp:ValidationSummary ID="ValidationSummary1" runat="server" />  
  38.     <asp:Button ID="Button1" runat="server" Text="Button"  />  
  39.     </div>  
  40.     </form>  
  41. </body>  
  42. </html>  

Conclusion

The article explained the steps involved in validating and submitting a form in ASP.NET 2.0. Also, the main functions within the framework involved in this process were identified and addressed briefly. ASP.NET 2.0 has a rich client side framework, and understanding the internal implementation helps us to leverage and customize its behavior.

posted on 2009-09-29 16:33  Wind Snail  阅读(556)  评论(0编辑  收藏  举报

导航