
Pro CSharp And The .NET 2.0 Platform (2005) [eng]
.pdf
884 CHAPTER 23 ■ ASP. NET 2 . 0 WEB PAGES AND WEB CONTROLS
Table 23-11. ASP.NET Validation Controls
Control |
Meaning in Life |
CompareValidator |
Validates that the value of an input control is equal to a given |
|
value of another input control or a fixed constant. |
CustomValidator |
Allows you to build a custom validation function that validates |
|
a given control. |
RangeValidator |
Determines that a given value is in a predetermined range. |
RegularExpressionValidator |
Checks if the value of the associated input control matches the |
|
pattern of a regular expression. |
RequiredFieldValidator |
Ensures that a given input control contains a value (i.e., is not |
|
empty). |
ValidationSummary |
Displays a summary of all validation errors of a page in a list, |
|
bulleted list, or single-paragraph format. The errors can be |
|
displayed inline and/or in a pop-up message box. |
|
|
All of the validator controls ultimately derive from a common base class named System.Web.UI.WebControls.BaseValidator, and therefore they have a set of common features. Table 23-12 documents the key members.
Table 23-12. Common Properties of the ASP.NET Validators
Member |
Meaning in Life |
ControlToValidate |
Gets or sets the input control to validate |
Display |
Gets or sets the display behavior of the error message in |
|
a validation control |
EnableClientScript |
Gets or sets a value indicating whether client-side validation is |
|
enabled |
ErrorMessage |
Gets or sets the text for the error message |
ForeColor |
Gets or sets the color of the message displayed when validation fails |
|
|
To illustrate the basics of working with validation controls, let’s create a new Web Site project named ValidatorCtrls. To begin, place four TextBox types (with four corresponding and descriptive Labels) onto your page. Next, place a RequiredFieldValidator, RangeValidator, RegularExpressionValidator, and CompareValidator type adjacent to each respective field. Finally, add a single Button and final Label (see Figure 23-32).

CHAPTER 23 ■ ASP. NET 2 . 0 WEB PAGES AND WEB CONTROLS |
885 |
Figure 23-32. The items to be validated
Now that you have a UI, let’s walk though the process of configuring each member.
The RequiredFieldValidator
Configuring the RequiredFieldValidator is straightforward. Simply set the ErrorMessage and ControlToValidate properties accordingly using the Visual Studio 2005 Properties window. The resulting *.aspx definition is as follows:
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="txtRequiredField" ErrorMessage="Oops! Need to enter data."> </asp:RequiredFieldValidator>
One nice thing about the RequiredFieldValidator is that it supports an InitialValue property. You can use this property to ensure that the user enters any value other than the initial value in the related TextBox. For example, when the user first posts to a page, you may wish to configure a TextBox to contain the value “Please enter your name”. Now, if you did not set the InitialValue property of the RequiredFieldValidator, the runtime would assume that the string “Please enter your name” is valid. Thus, to ensure a required TextBox is valid only when the user enters anything other than “Please enter your name”, configure your widgets as follows:
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="txtRequiredField" ErrorMessage="Oops! Need to enter data."
InitialValue="Please enter your name">
</asp:RequiredFieldValidator>

886 CHAPTER 23 ■ ASP. NET 2 . 0 WEB PAGES AND WEB CONTROLS
The RegularExpressionValidator
The RegularExpressionValidator can be used when you wish to apply a pattern against the characters entered within a given input field. To ensure that a given TextBox contains a valid U.S. Social Security number, you could define the widget as follows:
<asp:RegularExpressionValidator ID="RegularExpressionValidator1" runat="server" ControlToValidate="txtRegExp" ErrorMessage="Please enter a valid US SSN."
ValidationExpression="\d{3}-\d{2}-\d{4}">
</asp:RegularExpressionValidator>
Notice how the RegularExpressionValidator defines a ValidationExpression property. If you have never worked with regular expressions before, all you need to be aware of for this example is that they are used to match a given string pattern. Here, the expression "\d{3}-\d{2}\d{4}" is capturing a standard U.S. Social Security number of the form xxx-xx-xxxx (where x is any digit).
This particular regular expression is fairly self-explanatory; however, assume you wish to test for a valid Japanese phone number. The correct expression now becomes much more complex: "(0\d{1,4}-|\(0\d{1,4}\) ?)?\d{1,4}-\d{4}". The good news is that when you select the ValidationExpression property using the Properties window, you can pick from a predefined set of common regular expressions (see Figure 23-33).
Figure 23-33. Creating a regular expression via Visual Studio 2005
■Note If you are really into regular expressions, you will be happy to know that the .NET platform supplies two namespaces (System.Text.RegularExpressions and System.Web.RegularExpressions) devoted to the programmatic manipulation of such patterns.
The RangeValidator
In addition to a MinimumValue and MaximumValue property, RangeValidators have a property named Type. Because you are interested in testing the user-supplied input against a range of whole numbers, you need to specify Integer (which is not the default!):
<asp:RangeValidator ID="RangeValidator1" runat="server" ControlToValidate="txtRange" ErrorMessage="Please enter value between 0 and 100."
MaximumValue="100" MinimumValue="0" Type="Integer"> </asp:RangeValidator>

CHAPTER 23 ■ ASP. NET 2 . 0 WEB PAGES AND WEB CONTROLS |
887 |
The RangeValidator can also be used to test if a given value is between a currency value, date, floating-point number, or string data (the default setting).
The CompareValidator
Finally, notice that the CompareValidator supports an Operator property:
<asp:CompareValidator ID="CompareValidator1" runat="server" ControlToValidate="txtComparison"
ErrorMessage="Enter a value less than 20." Operator="LessThan" ValueToCompare="20">
</asp:CompareValidator>
Given that the role of this validator is to compare the value in the text box against another value using a binary operator, it should be no surprise that the Operator property may be set to values such as LessThan, GreaterThan, Equal, and NotEqual. Also note that the ValueToCompare is used to establish a value to compare against.
■Note The CompareValidator can also be configured to compare a value within another Web Form control (rather than a hard-coded value) using the ControlToValidate property.
To finish up the code for this page, handle the Click event for the Button type and inform the user he has succeeded in the validation logic:
protected void btnPostback_Click(object sender, EventArgs e)
{
lblValidationComplete.Text = "You passed validation!";
}
Now, navigate to this page using your browser of choice. At this point, you should not see any noticeable changes. However, when you attempt to click the Submit button after entering bogus data, your error message is suddenly visible. Once you enter valid data, the error messages are removed and postback occurs.
If you look at the HTML rendered by the browser, you see that the validator controls generate a client-side JavaScript function that makes use of a specific library of JavaScript functions (contained in the WebUIValidation.js file) that is automatically downloaded to the user’s machine. Once the validation has occurred, the form data is posted back to the server, where the ASP.NET runtime will perform the same validation tests on the web server (just to ensure that no along-the-wire tampering has taken place).
On a related note, if the HTTP request was sent by a browser that does not support client-side JavaScript, all validation will occur on the server. In this way, you can program against the validator controls without being concerned with the target browser; the returned HTML page redirects the error processing back to the web server.
Creating Validation Summaries
The final validation-centric topic we will examine here is the use of the ValidationSummary widget. Currently, each of your validators displays its error message at the exact place in which it was positioned at design time. In many cases, this may be exactly what you are looking for. However, on a complex form with numerous input widgets, you may not want to have random blobs of red text pop up. Using the ValidationSummary type, you can instruct all of your validation types to display their error messages at a specific location on the page.

888 CHAPTER 23 ■ ASP. NET 2 . 0 WEB PAGES AND WEB CONTROLS
The first step is to simply place a ValidationSummary on your *.aspx file. You may optionally set the HeaderText property of this type as well as the DisplayMode, which by default will list all error messages as a bulleted list.
<asp:ValidationSummary id="ValidationSummary1"
style="Z-INDEX: 123; LEFT: 152px; POSITION: absolute; TOP: 320px" runat="server" Width="353px"
HeaderText="Here are the things you must correct."> </asp:ValidationSummary>
Next, you need to set the Display property to None for each of the individual validators (e.g., RequiredFieldValidator, RangeValidator, etc.) on the page. This will ensure that you do not see duplicate error messages for a given validation failure (one in the summary pane and another at the validator’s location).
Last but not least, if you would rather have the error messages displayed using a client-side MessageBox, set the ShowMessageBox property to true and the ShowSummary property to false.
■Source Code The ValidatorCtrls project is included under the Chapter 23 subdirectory.
Summary
Building web applications requires a different frame of mind than is used to assemble traditional desktop applications. In this chapter, you began with a quick and painless review of some core web atoms, including HTML, HTTP, the role of client-side scripting, and server-side scripts using classic ASP.
The bulk of this chapter was spent examining the architecture of an ASP.NET page. As you have seen, each *.aspx file in your project has an associated System.Web.UI.Page-derived class. Using this OO approach, ASP.NET allows you to build more reusable and OO-aware systems. This chapter examined the use of master pages and various Web Form controls (including the new GridView and Wizard types). As you have seen, these GUI widgets are in charge of emitting HTML tags to the client side. The validation controls are server-side widgets that are responsible for rendering client-side JavaScript to perform form validation, without incurring a round-trip to the server.



CHAPTER 24 ■ ASP.NET 2.0 WEB APPLICATIONS |
891 |
updates for the current page (note that you are no longer using the private string member variable, therefore feel free to comment out or remove the definition altogether):
protected void btnSetCar_Click(object sender, EventArgs e)
{
Session["UserFavCar"] = txtFavCar.Text;
}
protected void btnGetCar_Click(object sender, EventArgs e)
{
lblFavCar.Text = (string)Session["UserFavCar"];
}
If you now run the application, the value of your favorite automobile will be preserved across postbacks, thanks to the HttpSessionState object manipulated with the inherited Session property.
■Source Code The SimpleStateExample files are included under the Chapter 24 subdirectory.
ASP.NET State Management Techniques
ASP.NET provides several mechanisms that you can use to maintain stateful information in your web applications. Specifically, you have the following options:
•Make use of ASP.NET view state.
•Make use of ASP.NET control state.
•Define application-level variables.
•Make use of the cache object.
•Define session-level variables.
•Interact with cookie data.
We’ll examine the details of each approach in turn, beginning with the topic of ASP.NET view state.
Understanding the Role of ASP.NET View State
The term view state has been thrown out numerous times here and in the previous chapter without a formal definition, so let’s demystify this term once and for all. Under classic ASP, web developers were required to manually repopulate the values of the incoming form widgets during the process of constructing the outgoing HTTP response. For example, if the incoming HTTP request contained five text boxes with specific values, the *.asp file needed to extract the current values (via the Form or QueryString collections of the Request object) and manually place them back into the HTTP response stream (needless to say, this was a drag). If the developer failed to do so, the caller was presented with a set of five empty text boxes!
Under ASP.NET, we are no longer required to manually scrape out and repopulate the values contained within the HTML widgets because the ASP.NET runtime will automatically embed a hidden form field (named __VIEWSTATE), which will flow between the browser and a specific page. The data assigned to this field is a Base64-encoded string that contains a set of name/value pairs that represent the values of each GUI widget on the page at hand.
The System.Web.UI.Page base class’s Init event handler is the entity in charge of reading the incoming values found within the __VIEWSTATE field to populate the appropriate member variables in the derived class (which is why it is risky at best to access the state of a web widget within the scope of a page’s Init event handler).

892 CHAPTER 24 ■ ASP.NET 2.0 WEB APPLICATIONS
Also, just before the outgoing response is emitted back to the requesting browser, the __VIEWSTATE data is used to repopulate the form’s widgets, to ensure that the current values of the HTML widgets appear as they did prior to the previous postback.
Clearly, the best thing about this aspect of ASP.NET is that it just happens without any work on your part. Of course, you are always able to interact with, alter, or disable this default functionality if you so choose. To understand how to do this, let’s see a concrete view state example.
Demonstrating View State
First, create a new ASP.NET web application called ViewStateApp. On your initial *.aspx page, add a single ASP.NET ListBox web control and a single Button type. Handle the Click event for the Button to provide a way for the user to post back to the web server:
protected void btnDoPostBack_Click(object sender, EventArgs e)
{
// This is just here to allow a postback.
}
Now, using the Visual Studio 2005 Properties window, access the Items property and add four ListItems to the ListBox. The result looks like this:
<asp:ListBox ID="myListBox" runat="server"> <asp:ListItem>Item One</asp:ListItem> <asp:ListItem>Item Two</asp:ListItem> <asp:ListItem>Item Three</asp:ListItem> <asp:ListItem>Item Four</asp:ListItem>
</asp:ListBox>
Note that you are hard-coding the items in the ListBox directly within the *.aspx file. As you already know, all <asp:> definitions found within an HTML form will automatically render back their HTML representation before the final HTTP response (provided they have the runat="server" attribute).
The <%@Page%> directive has an optional attribute called enableViewState that by default is set to true. To disable this behavior, simply update the <%@Page%> directive as follows:
<%@ Page EnableViewState ="false"
Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
So, what exactly does it mean to disable view state? The answer is, it depends. Given the previous definition of the term, you would think that if you disable view state for an *.aspx file, the values within your ListBox would not be remembered between postbacks to the web server. However, if you were to run this application as is, you might be surprised to find that the information in the ListBox is retained regardless of how many times you post back to the page. In fact, if you examine the source HTML returned to the browser, you may be further surprised to see that the hidden __VIEWSTATE field is still present:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTY1MjcxNTcxNmRkOXbNzW5+R2VDhNWtEtHMM+yhxvU=" />
The reason why the view state string is still visible is the fact that the *.aspx file has explicitly defined the ListBox items within the scope of the HTML <form> tags. Thus, the ListBox items will be autogenerated each time the web server responds to the client.
However, assume that your ListBox is dynamically populated within the code-behind file rather than within the HTML <form> definition. First, remove the <asp:ListItem> declarations from the current *.aspx file:
<asp:ListBox ID="myListBox" runat="server"> </asp:ListBox>

CHAPTER 24 ■ ASP.NET 2.0 WEB APPLICATIONS |
893 |
Next, fill the list items within the Load event handler of within your code-behind file:
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
// Fill ListBox dynamically! myListBox.Items.Add("Item One"); myListBox.Items.Add("Item Two"); myListBox.Items.Add("Item Three"); myListBox.Items.Add("Item Four");
}
}
If you post to this updated page, you will find that the first time the browser requests the page, the values in the ListBox are present and accounted for. However, on postback, the ListBox is suddenly empty. The first rule of ASP.NET view state is that its effect is only realized when you have widgets whose values are dynamically generated through code. If you hard-code values within the *.aspx file’s <form> tags, the state of these items is always remembered across postbacks (even when you set enableViewState to false for a given page).
Furthermore, view state is most useful when you have a dynamically populated web widget that always needs to be repopulated for each and every postback (such as an ASP.NET GridView, which is always filled using a database hit). If you did not disable view state for pages that contain such widgets, the entire state of the grid is represented within the hidden __VIEWSTATE field. Given that complex pages may contain numerous ASP.NET web controls, you can imagine how large this string would become. As the payload of the HTTP request/response cycle could become quite heavy, this may become a problem for the dial-up web surfers of the world. In cases such as these, you may find faster throughput if you disable view state for the page.
If the idea of disabling view state for the entire *.aspx file seems a bit too aggressive, recall that every descendent of the System.Web.UI.Control base class inherits the EnableViewState property, which makes it very simple to disable view state on a control-by-control basis:
<asp:GridView id="myHugeDynamicallyFilledDataGrid" runat="server"
EnableViewState="false"> </asp:GridView>
■Note Be aware that ASP.NET pages reserve a small part of the __VIEWSTATE string for internal use. Given this, you will find that the __VIEWSTATE field will still appear in the client-side browser even when the entire page (and all the controls) have disabled view state.
Adding Custom View State Data
In addition to the EnableViewState property, the System.Web.UI.Control base class also provides an inherited property named ViewState. Under the hood, this property provides access to a System.Web.UI.StateBag type, which represents all the data contained within the __VIEWSTATE
field. Using the indexer of the StateBag type, you can embed custom information within the hidden __VIEWSTATE form field using a set of name/value pairs. Here’s a simple example:
protected void btnAddToVS_Click(object sender, EventArgs e)
{
ViewState["CustomViewStateItem"] = "Some user data"; lblVSValue.Text = (string)ViewState["CustomViewStateItem"];
}