Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Pro CSharp And The .NET 2.0 Platform (2005) [eng]

.pdf
Скачиваний:
111
Добавлен:
16.08.2013
Размер:
10.35 Mб
Скачать

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.

C H A P T E R 2 4

■ ■ ■

ASP.NET 2.0 Web Applications

The previous chapter concentrated on the composition and behavior of ASP.NET pages and the web controls they contain. This chapter builds on these basics by examining the role of the HttpApplication type. As you will see, the functionality of HttpApplication allows you to intercept numerous events that enable you to treat your web applications as a cohesive unit, rather than a set of stand-alone

*.aspx files.

In addition to investigating the HttpApplication type, this chapter also addresses the allimportant topic of state management. Here you will learn the role of view state, control state, and sessionand application-level variables, as well as a state-centric entity provided by ASP.NET termed the application cache. Once you have a solid understanding of the state management techniques offered by the .NET platform, the chapter wraps up with a discussion of the role of the Web.config file and shows various configuration-centric techniques.

The Issue of State

At the beginning of the last chapter, I pointed out that HTTP is a stateless wire protocol. This very fact makes web development extremely different from the process of building an executable assembly. For example, when you are building a Windows Forms application, you can rest assured that any member variables defined in the Form-derived class will typically exist in memory until the user explicitly shuts down the executable:

public partial class MainWindow : Form

{

// State data!

private string userFavoriteCar;

...

}

In the world of the World Wide Web, however, you are not afforded the same luxurious assumption. To prove the point, create a new ASP.NET website (named SimpleStateExample) that has a single *.aspx file. Within the code-behind file, define a page-level string variable named userFavoriteCar:

public partial class _Default : Page

{

// State data?

private string userFavoriteCar;

...

}

889

890 CHAPTER 24 ASP.NET 2.0 WEB APPLICATIONS

Next, construct the web UI as shown in Figure 24-1.

Figure 24-1. The UI for the simple state page

The server-side Click event handler for the Set button will allow the user to assign the string variable using the value within the TextBox:

protected void btnSetCar_Click(object sender, EventArgs e)

{

// Store favorite car in member variable. userFavoriteCar = txtFavCar.Text;

}

while the Click event handler for the Get button will display the current value of the member variable within the page’s Label widget:

protected void btnGetCar_Click(object sender, EventArgs e)

{

// Set label text to value of member variable. lblFavCar.Text = userFavoriteCar;

}

Now, if you were building a Windows Forms application, you would be right to assume that once the user sets the initial value, it would be remembered throughout the life of the desktop application. Sadly, when you run this web application, you will find that each time you post back to the web server, the value of the userFavoriteCar string variable is set back to the initial empty value; therefore, the Label’s text is continuously empty.

Again, given that HTTP has no clue how to automatically remember data once the HTTP response has been sent, it stands to reason that the Page object is destroyed instantly. Therefore, when the client posts back to the *.aspx file, a new Page object is constructed that will reset any page-level member variables. This is clearly a major dilemma. Imagine how painful online shopping would be if every time you posted back to the web server, any and all information you previously entered (such as the items you wish to purchase) were discarded. When you wish to remember information regarding the users who are logged on to your site, you need to make use of various state management techniques.

Note This issue is in no way limited to ASP.NET. Java servlets, CGI applications, classic ASP, and PHP applications all must contend with the thorny issue of state management.

To remember the value of the userFavoriteCar string type between postbacks, you are required to store the value of this string type within a session variable. You will examine the exact details of session state in the pages that follow. For the sake of completion, however, here are the necessary

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"];

}