MCAD/MCSD: Implementing Navigation for the User Interface

Date: Mar 14, 2003

Return to the article

Brush up on your navigation implementation and look at the Microsoft-specified objectives for the Creating User Services section of Exam 70-315, Developing and Implementing Web Applications with Microsoft Visual C# .NET and Microsoft Visual Studio .NET.

Objectives

This chapter covers the following Microsoft-specified objectives for the "Creating User Services" section of Exam 70-315, "Developing and Implementing Web Applications with Microsoft Visual C# .NET and Microsoft Visual Studio .NET":

Implement navigation for the user interface.

Use and edit intrinsic objects. Intrinsic objects include response, request, session, server, and application.

Outline

Study Strategies

Introduction

Development of Web applications is a different game compared to developing Windows applications. One of the major challenges that a Web developer faces while developing a Web application is the disconnected nature of Web application. Traditionally, programmers had to write a lot of additional code to maintain state between page postback and navigation. ASP.NET provides a better model of programming by incorporating the tasks related to state management as part of the programming framework itself so that developers spend less time in plumbing work and more on developing the actual business logic.

In this chapter, I'll present various state management features provided by ASP.NET. I'll discuss both client-side techniques as well as server-side techniques for state management.

I'll also discuss the ASP.NET intrinsic objects that are available to you via the Page class. You'll see how these objects can help you fulfill various common Web development requirements.

Finally, I'll use the intrinsic objects to demonstrate various methods you can use to navigate from one page to another. I'll also compare various navigation techniques so that you can choose the appropriate technique for a given scenario.

Roundtrip and Postback

Implement navigation for the user interface: Manage data during postback events.

Web applications have a distributed execution model. When a user interacts with a Web form, the browser might respond to some of the user actions by executing client-side scripts while some other actions that require server resources must be sent to the Web server for processing. When server-side processing is involved, a typical interactive user session with a Web form consists of the following steps:

  1. User requests a Web form from the Web server.

  2. Web Server responds back with the requested Web form.

  3. User enters the data and submits the form to the Web server.

  4. Web Server processes the form and sends the result back to the user.

Step 3 is also referred to as a page postback, whereas steps 3 and 4 are collectively referred to as a roundtrip. A roundtrip involves making a complete trip over the network to the Web server and getting the response back.

The Web applications use HTTP to establish communication between the Web browser and the Web server. HTTP is disconnected in nature, which means that the life cycle of a Web page is just a single roundtrip. Every time a Web server responds to a page request, it freshly creates the resources required to create the page, sends the page to the requesting client and destroys the page resources from the server. Between two page requests, Web server and the clients are disconnected with each other, and values of page variables and controls are not preserved across the page requests.

This model of execution allows a Web server to support a large number of clients because each client request occupies the server resources only for a short duration. However, the disconnected nature of HTTP provides a major challenge to the Web developers to implement the following functionality in their applications:

ASP.NET provides solutions to these problems built right in to its framework. As an ASP.NET developer, you only need to write a minimum amount of code to achieve these functionalities in your application. From my discussion about server controls in Chapter 2, "Controls," you already know that ASP.NET provides a set of server controls that automatically retain their value across page postbacks. You'll learn how ASP.NET actually retains the state for server controls later in this chapter in a section titled "State Management." For now, I'll talk about two properties of the Page class—IsPostBack and SmartNavigation—that provide the other two functionalities from the previous list.

The IsPostBack Property

The IsPostBack property of the Page class returns true when a page is being loaded in response to a client postback. If the page is being requested for the first time, the value of the IsPostBack property is false.

A typical case in which you would like to make use of this distinction is when you do not want the server to execute some costly initialization operations for each page postback. Instead, you would like the initializations to be performed only with the first request to the page.

Step by Step 3.1 helps you understand roundtrip and postback operations and demonstrates the use of the IsPostBack property.

STEP BY STEP

3.1 Using the IsPostBack Property

  1. Create a new Visual C# ASP.NET Web application project. Name the project 315C03.

  2. Add a new Web form to the project. Name the Web form StepByStep3_1.aspx. Change the pageLayout property of the DOCUMENT element to FlowLayout.

  3. Add a DropDownList Web server control (ddlCategories) to the form. Set its AutoPostBack to true and TabIndex to 1 (see Figure 3.1).

  4. Add a Label control (lblQuestion) to the Web form.

  5. Add a TextBox control (txtTitle) and set its AutoPostBack to true and TabIndex to 2. Add another TextBox (txtMessage) and set its TabIndex to 3 and TextMode to MultiLine (see Figure 3.1).

  6. Add a Button control (btnPost) and set its Text to Post a message. Place a Label control (lblWeblog) at the end of the form as shown in Figure 3.1.

  7. Figure 3.1 The design of a form that allows you to post messages to a Weblog.

  8. Switch to the code view of the Web form and add the following code to the Page_Load() event handler:

  9. private void Page_Load(
      object sender, System.EventArgs e)
    {
      if (!Page.IsPostBack)
      {
        // If page is requested for the first time
        ddlCategories.Items.Add("Web development");
        ddlCategories.Items.Add(
          "Programming Languages");
        ddlCategories.Items.Add("Certifications");
      }
      else
      {
        // On postback, change the case of 
        // the textbox's text
        txtTitle.Text = txtTitle.Text.ToUpper();
      }
      // Set the text of the label control 
      // on each page load
      lblQuestion.Text = 
       "What do you want to write about "
       + ddlCategories.SelectedItem.Text + " today?";
    }
  10. Attach the following event handler to the Click event of the Post button:

  11. private void btnPost_Click(
       object sender, System.EventArgs e)
    {
      // Format the data entered by the user and
      // append it to the existing contents of lblWeblog
      lblWeblog.Text = "<b>" + 
           ddlCategories.SelectedItem.Text
           + " :: " + txtTitle.Text + "</b> (" 
           + DateTime.Now.ToString() + ")<hr>" 
           + txtMessage.Text + "<p>" 
           + lblWeblog.Text + "</p>";
    }
  12. Set StepByStep3_1.aspx as the start page in the project.

  13. Run the project. Use the Tab key to navigate between various fields and publish a few entries to the Weblog as shown in Figure 3.2.

Figure 3.2 The Web form retains state for both postback as well as non-postback controls.

In Step by Step 3.1, I am using the event handler for the Load event of the Page class to check if the page is loaded by a postback operation. If that is the case, I skip executing the code for adding items to the drop-down list.

You also note that the navigation between controls is not smooth. When the form returns after a postback, it does not remember the active control. However, you have a solution to this problem with the help of the SmartNavigation property.

The SmartNavigation Property

ASP.NET has a feature called smart navigation that can greatly enhance the user experience of a Web page for users of Internet Explorer 5.0 or higher browsers. The following list summarizes the enhancements provided by smart navigation:

Smart navigation is specified by the SmartNavigation property of the Page class. The default value of this property is false, which disables smart navigation for the Web form.

Smart Navigation

Smart navigation is only supported in Internet Explorer 5.0 or later browsers. Therefore, when you are targeting an application for a generic browser, this feature won't be very helpful.

In most cases, you should not set the SmartNavigation property directly in the code. Instead, you should use the SmartNavigation attribute of the Page directive. Using the SmartNavigation attribute of the Page directive automatically generates the correct code for setting the SmartNavigation property of the Page class, when the Web form is compiled to create a Page derived class.

Step by Step 3.2 enhances the Web form created in Step by Step 3.1 to use the smart navigation feature.

STEP BY STEP

3.2 Using the Smart Navigation Feature of ASP.NET

  1. Make a copy of StepByStep3_1 and save it as StepByStep3_2. Make sure that you change all references of StepByStep3_1 to StepByStep3_2 in both the ASPX as well as the CS file.

  2. Switch to the HTML view of the StepByStep3_2.aspx file and modify the Page directive to the following:

  3. <%@ Page language="c#" 
         Codebehind="StepByStep3_2.aspx.cs" 
         AutoEventWireup="false" 
         Inherits="_315C03.StepByStep3_2" 
         SmartNavigation="true"
    %>
  4. Set StepByStep3_2.aspx as the start page. Build the project and Browse to StepByStep3_2.aspx using Internet Explorer 5.0 or higher.

  5. Use the Tab key to navigate between various fields, publish a few messages, and observe the enhancements because of the smart navigation feature.

In a corporate scenario in which you are sure about the browsers used by the users, you might want to turn on smart navigation for the complete Web application instead of individual files. In that case, you can make the following changes to the web.config file:

<configuration> 
   <system.web> 
     <pages SmartNavigation="true"/> 
   </system.web> 
</configuration> 

ASP.NET Intrinsic Objects

Use and edit intrinsic objects. Intrinsic objects include response, request, session, server, and application.

ASP.NET provides intrinsic objects to enable low-level access to the Web application framework. With the help of these intrinsic objects, you can work directly with the underlying HTTP streams, server, session, and application objects. The intrinsic objects can be accessed in a Web form through the properties of the Page class. Table 3.1 lists the important intrinsic objects and the properties of the Page class to which they are mapped.

Table 3.1 Intrinsic Objects and Their Mappings to the Page Class Properties

Intrinsic Object

Property of the Page Class

HttpRequest

Request

HttpResponse

Response

HttpServerUtility

Server

HttpApplicationState

Application

HttpSessionState

Session


I'll discuss the HttpRequest, HttpResponse, and HttpServerUtility objects in the following section. The other two objects, HttpApplicationState and HttpSessionState, are discussed later in this chapter in the section "State Management."

The HttpRequest Object

The HttpRequest object . represents the incoming request from the client to the Web server. The request from the client can come in two ways—GET or POST. GET attaches the data with the URL, whereas POST embeds the data within the HTTP request body.

The requested page and its details are encapsulated in an HttpRequest object. The HttpRequest intrinsic object can be accessed by the Request property of the Page class. Tables 3.2 and 3.3 list the properties and methods of the HttpRequest class, respectively. Because the HttpRequest class provides information about the request sent by the client, all the properties are read-only except the Filter property.

Table 3.2 Properties of the HttpRequest Class

Property

Description

AcceptTypes

Specifies the MIME types that the client browser accepts.

ApplicationPath

Represents the application's virtual application root path on the server.

Browser

Provides access to the capabilities and characteristics of the requesting browser.

ClientCertificate

Represents the certificate, if any, sent by the client for secure communications.

ContentEncoding

Represents the character encoding (such as UTF7, ASCII, and so on) for the entity body.

ContentLength

Specifies the length in bytes of the request.

ContentType

Specifies the MIME type of the incoming request.

Cookies

Represents the cookies collection that is sent by the client to the server.

CurrentExecutionFilePath

Specifies the virtual path of the current executing page on the Web server.

FilePath

Specifies the virtual path of the file on the Web server.

Files

Represents the file collection that is posted by the client to the Web server.

Filter

Represents a stream that is applied as a filter on the incoming request.

Form

Specifies the contents of a form posted to the server.

Headers

Represents the HTTP headers passed in with the incoming request.

HttpMethod

Represents the method of the HTTP request (for example, GET, POST, or HEAD).

InputStream

Represents the stream that contains the incoming HTTP request body.

IsAuthenticated

Indicates whether the client has been authenticated to the Web site.

IsSecureConnection

Indicates whether the client connection is over a secure HTTPS connection.

Params

Represents the form, query string, cookies, and server variables collection of the current request.

Path

Specifies the virtual path of the current request, along with additional path information.

PathInfo

Specifies the additional path information of the current request.

PhysicalApplicationPath

Specifies the physical file system path of the application's root directory.

PhysicalPath

Specifies the physical file system path of the current request on the Web server.

QueryString

Represents the query string collection sent by the client to the Web server through the URL.

RawUrl

Specifies the URL portion of the current request, excluding the domain information.

RequestType

Represents the type of request (GET or POST) made by the client.

ServerVariables

Represents the collection of Web server variables.

TotalBytes

Represents the total number of bytes posted to the server in the current request.

Url

Specifies information about the current URL request.

UrlReferrer

Specifies the URL of the client's previous request that linked to the current URL request.

UserAgent

Represents the browser being used by the client.

UserHostAddress

Represents the IP address of the requesting client's machine.

UserHostName

Represents the Domain Name System (DNS) name of the requesting client's machine.

UserLanguages

Specifies the languages preferred by the client's browser.


Table 3.3 Methods of the HttpRequest Class

Method

Description

BinaryRead()

Reads the specified number of bytes from the request stream. This method is provided for backward compatibility; you should use InputStream property instead.

MapImageCoordinates()

Returns the coordinates of a form image that is sent to the server in the current request.

MapPath()

Returns the physical file system path of the file for a specified virtual path of a Web server.

SaveAs()

Saves the current HTTP request into a disk file, with an option to include or exclude headers.


CurrentExecutionFilePath

This property of the HttpRequest class returns the file path of the currently executing page. When using the server-side redirection methods such as Server.Execute() and Server.Transfer(), the FilePath property returns the path to the original page, whereas CurrentExecutionFilePath returns the path to the currently executing page.

Step by Step 3.3 displays some of the path-related properties of the HttpRequest object and calls the MapPath() method to get the physical file system path for a specified virtual path. It also displays the header information sent by the client to the server when the StepByStep3_3.aspx page is requested from the server.

STEP BY STEP

3.3 Using the HttpRequest Intrinsic Object

  1. Add a new Web form to the project. Name the Web form StepByStep3_3.aspx. Change the pageLayout property of the DOCUMENT element to FlowLayout.

  2. Add a Label control (lblInfo) to the Web form.

  3. Switch to the code view of the form. Add the following using directive at the top of the code-behind file:

  4. using System.Text;

  5. Add the following code to the Page_Load() event handler:

  6. private void Page_Load(
      object sender, System.EventArgs e)
    {
      StringBuilder sbInfo = new StringBuilder();
    
      // Display some of the path related properties 
      // of the HttpRequest object
      sbInfo.Append("The Url of the ASPX page: " + 
        Request.Url + "<br>");
      sbInfo.Append("The Virtual File Path: " + 
        Request.FilePath + "<br>");
      sbInfo.Append("The Physical File Path: " + 
        Request.PhysicalPath + "<br>");
      sbInfo.Append("The Application Path: " + 
        Request.ApplicationPath + "<br>");
      sbInfo.Append("The Physical Application Path: " +
        Request.PhysicalApplicationPath + "<br>");
    
      // Display the request header
      sbInfo.Append("Request Header:");
      sbInfo.Append("<br>");
      NameValueCollection nvcHeaders = Request.Headers;
      String[] astrKeys = nvcHeaders.AllKeys;
      // Iterate through all header keys 
      // and display their values
      foreach (String strKey in astrKeys)
      {
        sbInfo.Append(strKey + ": " + 
          nvcHeaders[strKey].ToString());
        sbInfo.Append("<br>");
      }
      // Call MapPath() method to find the physical path
      // of StepByStep3_2.aspx
      sbInfo.Append(
        "The physical path of StepByStep3_2.aspx: ");
      sbInfo.Append(
        Request.MapPath("StepByStep3_2.aspx"));
      lblInfo.Text = sbInfo.ToString();
    }
  7. Set StepByStep3_3.aspx as the start page in the project.

  8. Run the project. You should see the Web form displaying the properties for the current request, as shown in Figure 3.3.

Figure 3.3 The Request property of the Page class returns an HttpRequest object that gives access to the HTTP values sent by a client during a Web request.

Some properties of the HttpRequest object—such as Form, QueryString, Headers, and so on—return a NameValueCollection containing a collection of key-value pairs of their contents. Step by Step 3.3 shows how to iterate through this collection by iterating through the keys of the Headers collection and displaying the key and value of each header sent by the client.

The HttpResponse Object

The HttpResponse object represents the response sent back to the client from the Web server. It contains properties and methods that provide direct access to the response stream and allow you to set its behavior and operations. The Response property of the Page class provides access to the HttpResponse object. Tables 3.4 and 3.5 list the properties and methods of the HttpResponse class, respectively.

Table 3.4 Properties of the HttpResponse Class

Property

Description

Buffer

Indicates whether output to the response stream needs to be buffered and sent to the client after the entire page is processed. This property is provided for backward compatibility; the BufferOutput property should be used instead.

BufferOutput

Indicates whether the output to the response stream needs to be buffered and then sent to the client after the entire page is processed. The default is true.

Cache

Represents the caching policy of the page. The policy controls where caching can be done, the expiration time, and so on.

CacheControl

Specifies where the caching should be done. The possible values are Public and Private.

Charset

Represents the character set of the output stream. If set to null, the content-type header will be suppressed.

ContentEncoding

Represents the character set of the response output stream.

ContentType

Represents the MIME type for the outgoing response stream like text/html, text/xml, and so on.

Cookies

Represents the cookies collection that is sent by the server to the client.

Expires

Indicates the number of minutes until the page is cached by the client browser.

ExpiresAbsolute

Indicates the specific date and time until the page is cached by the client browser.

Filter

Represents a stream that is applied as a filter to the outgoing response.

IsClientConnected

Indicates whether the client is connected to the server. This property is very helpful when running a lengthy request.

Output

Allows writing text output to the outgoing response.

OutputStream

Allows writing binary output to the outgoing response.

Status

Specifies the status of the HTTP output that is sent to the client. This property returns both the status code and the text description of the status (for example, 200 OK).

StatusCode

Specifies the numeric representation of the status of the HTTP output sent to the client (for example, 200, 302, and so on).

StatusDescription

Specifies the text representation of the status of the HTTP output sent to the client. (for example, OK, Redirect, and so on).

SupressContent

Indicates whether the content in the page should be suppressed and not sent to the client.


Caching Policy

The properties CacheControl, Expires, and ExpiresAbsolute are provided for backward compatibility. You should instead use the HttpCachePolicy object's methods to set the caching policy. This object is returned by the Cache property. Setting caching policy is discussed in Chapter 15, "Configuring a Web Application."

Table 3.5 Methods of the HttpResponse Class

Method

Description

AddCacheItemDependencies()

Makes the validity of the cache item dependent on the other items in the cache.

AddCacheItemDependency()

Makes the validity of the cache item dependent on another item in the cache.

AddFileDependencies()

Adds a group of files to the collection on which the current response depends.

AddFileDependency()

Adds a file to the collection on which the current response depends.

AddHeader()

Adds an HTTP header to the outgoing response stream. This method is provided for backward compatibility with ASP.

AppendHeader()

Adds an HTTP header to the outgoing response stream.

AppendToLog()

Adds information to the IIS Web log file.

BinaryWrite()

Allows writing binary data such as an image file or PDF file to the response stream.

Clear()

Clears the entire response stream buffer, including ts contents and headers.

ClearContent()

Clears the entire content portion of the response stream buffer.

ClearHeaders()

Clears the headers portion of the response stream buffer.

Close()

Closes the response object and the socket connection to the client.

End()

Stops the execution of the page after flushing the output buffer to the client.

Flush()

Flushes the currently buffered content out to the client.

Pics()

Adds a PICS-label HTTP header to the outgoing response.

Redirect()

Redirects the client browser to any URL. This method requires an additional roundtrip to the browser.

RemoveOutputCacheItem()

Removes all cache items for the path specified.

Write()

Writes output to the outgoing response.

WriteFile()

Writes a file to the outgoing response.


Step by Step 3.4 shows the use of HttpResponse object methods and properties to create a response that displays the File Download dialog box and allows the user to download a text file from the Web server to the client's machine.

STEP BY STEP

3.4 Using the HttpResponse Intrinsic Object

  1. Add a new Web form to the project. Name the Web form StepByStep3_4.aspx. Change the pageLayout property of the DOCUMENT element to FlowLayout.

  2. Add a text file to the project that contains some data that needs to be downloaded. Name it Summary.txt.

  3. Add a LinkButton control (lbtnDownload) to the Web form with its Text property set to Download Summary.txt.

  4. Double-click the lbtnDownload control and add the following code to the Click event handler:

  5. private void lbtnDownload_Click(object sender, 
      System.EventArgs e)
    {
      // Append a Header to the response to force a
      // Download of Summary.txt as an attachment
      Response.AppendHeader("Content-Disposition", 
        "Attachment;FileName=" + "Summary.txt");
    
      // Set the Content type to text/plain 
      // As the download file is a TXT file
      Response.ContentType = "text/plain";
    
      // Write the file to the Response
      Response.WriteFile("Summary.txt");
    
      // Stop further execution of the page
      Response.End();
    }
  6. Set StepByStep3_4.aspx as the start page in the project.

  7. Run the project. Click the link button. You should see a File Download dialog box, as shown in Figure 3.4. After the download, open the file to verify that the file has been successfully downloaded.

Figure 3.4 The File Download dialog box provides the interface to download a file from the Web server.

The HttpServerUtility Object

The HttpServerUtility object contains utility methods and properties to work with the Web server. It contains methods to enable HTML/URL encoding and decoding, execute or transfer to an ASPX page, create COM components, and so on. The Server property of the Page class provides access to the HttpServerUtility object. Tables 3.6 and 3.7 list the properties and methods of the HttpServerUtility class, respectively.

Table 3.6 Properties of the HttpServerUtility Class

Property

Description

MachineName

Returns the name of the server that hosts the Web application.

ScriptTimeout

Indicates the number of seconds that are allowed to elapse when processing the request before a timeout error is sent to the client.


Table 3.7 Methods of the HttpServerUtility Class

Method

Description

ClearError()

Clears the last exception from memory. This method is discussed in Chapter 4, "Error Handling for the User Interface."

CreateObject()

Creates a COM object on the server. This method is discussed in Chapter 10, "Working with Legacy Code."

CreateObjectFromClsid()

Creates a COM object on the server identified by a specified class identifier (CLSID).

Execute()

Executes an ASPX page within the current requested page.

GetLastError()

Returns the last exception that occurred on the Web server. This method is discussed in Chapter 4.

HtmlDecode()

Decodes a string that has been previously encoded to eliminate invalid HTML characters.

HtmlEncode()

Encodes a string converting any characters that are illegal in HTML for transmission over HTTP.

MapPath()

Returns the physical path for a specified virtual path on a Web server.

Transfer()

Allows the transfer of ASPX page execution from the current page to another ASPX page on the same Web server.

UrlDecode()

Decodes a string that has been previously encoded to eliminate invalid characters for transmission over HTTP in a URL.

UrlEncode()

Encodes a string converting any characters that are illegal in URL for HTTP transmission.

UrlPathEncode()

Encodes the path portion of the URL string for safe transmission over HTTP.


STEP BY STEP

3.5 Using the HttpServerUtility Intrinsic Object

  1. Add a new Web form to the project. Name the Web form StepByStep3_5.aspx. Change the pageLayout property of DOCUMENT element to FlowLayout.

  2. Add the following code to the Page_Load() event handler:

  3. private void Page_Load(
      object sender, System.EventArgs e)
    {
      // Write to the response
      // using the Server.HtmlEncode() method
      // so that the browser does not parse
      // the text into HTML elements
      Response.Write(Server.HtmlEncode(
        "To include a title in the title bar, " + 
        "enclose your chosen title between the " + 
        "pairs of the <title>...</title> element " + 
        "in the HTML <head> element. "));
    
      Response.Write(Server.HtmlEncode(
        "For example, <title> " + 
        "Using the HtmlEncode() method </title>."));
    }
  4. Set StepByStep3_5.aspx as the Start page in the project.

  5. Run the project. You should see that the browser does not parse the HTML <title> elements written to the response, as shown in Figure 3.5, because of the use of the HtmlEncode() method of the HttpServerUtility class.

Figure 3.5 The HtmlEncode() method of the HttpServerUtility object. HTML encodes a string to be displayed in the browser.

I will discuss various other methods of the HttpServerUtility object throughout the course of this book.

Guided Practice Exercise 3.1

Several Web sites collect statistics about the browsers, operating system, and other settings on their users' computers. This data helps the Web sites customize their contents to target a large number of users. A common requirement for Web applications is to find out the browser versions of their users and then serve them files that are optimized for that particular browser version.

In this exercise, you are required to create a Web form that displays the following information about the client browser: the browser name, version, platform of the client's computer, the CLR version installed, JavaScript support, ECMA version, MS DOM version, and the W3C XML DOM version supported by the browser.

You can use the Request.Browser property to get access to the HttpBrowserCapabilities object that provides various properties that contain information on the capabilities of the client's browser.

How would you create a Web form that allows the Web page to get information about the browser?

You should try working through this problem on your own first. If you are stuck, or if you'd like to see one possible solution, follow these steps:

  1. Open the project 315C03. Add a new Web form GuidedPracticeExercise3_1.aspx to the project. Change the pageLayout property of DOCUMENT element to FlowLayout.

  2. Add a Label control (lblInfo) to the Web form.

  3. Switch to the code view of the form. Add the following using directive at the top of the code-behind file:

  4. using System.Text;
  5. Add the following code to the Page_Load() event handler:

  6. private void Page_Load(
      object sender, System.EventArgs e)
    {
      StringBuilder sbText = new StringBuilder();
    
      // Get the reference to the 
      // HttpBrowserCapabilities object 
      HttpBrowserCapabilities browser = Request.Browser;
    
      // Display the properties of the 
      // HttpBrowserCapabilities Class
      sbText.AppendFormat("Browser : " + 
        browser.Browser + "<br>");
      sbText.AppendFormat("Browser Version: " + 
        browser.Version + "<br>");
      sbText.AppendFormat("Client's Platform: " + 
        browser.Platform + "<br>");
      sbText.AppendFormat(".NET CLR Version: " + 
        browser.ClrVersion + "<br>");
      sbText.AppendFormat("ECMA Script Version: " + 
        browser.EcmaScriptVersion + "<br>");
      sbText.AppendFormat("JavaScript Support: " + 
        browser.JavaScript + "<br>");
      sbText.AppendFormat(
       "Microsoft HTML Document Object Model Version: "
        + browser.MSDomVersion + "<br>");
      sbText.AppendFormat(
        "World Wide Web (W3C) XML Document " + 
        " Object Model Version: " + 
        browser.W3CDomVersion + "<br>");
    
      lblInfo.Text=sbText.ToString();
    }
  7. Set GuidedPracticeExercise3_1.aspx as the start page in the project.

  8. Run the project. You should see the Web form displaying the properties of the browser as shown in Figure 3.6.

Figure 3.6 The HttpBrowserCapabilities object provides access to the capabilities of the client's browser.

If you have difficulty following this exercise, review the section "The HttpRequest Object" earlier in this chapter and perform Step by Step 3.3. Also, look at the .NET Framework documentation for the System.Web.HttpBrowserCapabilities class. After doing this review, try this exercise again.

REVIEW BREAK

ASP.NET Application

An ASP.NET application is made up of the Web forms, assemblies, and other files stored within a virtual Web directory marked as an IIS application.

When ASP.NET receives a request for a resource in an ASP.NET application, it instantiates an HttpApplication object. The HttpApplication object then takes over the processing of incoming request. An HttpApplication object can only handle one request at a time. To process multiple simultaneous requests, ASP.NET needs to create multiple HttpApplication objects.

For the sake of optimization, instead of destroying the HttpApplication object, ASP.NET maintains a pool of HttpApplication objects. When a new HTTP request arrives, ASP.NET reuses one of the objects from this pool rather than creating a new HttpApplication object from scratch.

The HttpApplication class defines the methods, properties, and events common to all application objects within an ASP.NET application. If you want to customize the behavior of an HttpApplication object, you can derive a class from the HttpApplication class and override the event handlers of the base class for various application level events. An easy way to do this is by using the global.asax file.

The global.asax File

ASP.NET provides an easy way to customize your applications by using the global.asax file. This optional file resides in the root directory of an ASP.NET application. The global.asax file defines a class named Global that derives from the HttpApplication class. When ASP.NET notices that the global.asax file is present for an application, rather than using the implicitly created HttpApplication object, ASP.NET creates instances of the class defined in the global.asax file to handle requests for your application.

Visual Studio .NET automatically creates a global.asax file when you create an ASP.NET Web application project. As with Web forms, Visual Studio .NET creates a code-behind version of the global.asax file. When you make any changes to the code-behind file for global.asax, you must precompile the file before the server can detect those changes. However, it is also possible to create a single file implementation of the global.asax file. In that case, instead of being precompiled, the global.asax file will be dynamically compiled at runtime by ASP.NET.

The global.asax File Is Protected

You use the global.asax file to provide event handlers for various application level events. For security reasons, ASP.NET restricts users of your application from downloading any file with the extension .asax.

Global Event Handlers

The global.asax file is an appropriate place to handle events that are not specific to a Web form, but rather apply to an application as a whole. I'll call these events global events and classify them in two categories—Application and session level events and Per-Request events.

Application and Session Level Events

Application and session level events are fired to signal the start and end of the application or a user session. These events can be handled using the predefined event handlers in the global.asax file shown in Table 3.8.

Table 3.8 Application and Session Level Event Handlers in the global.asax File

Event Handler

Purpose

Application_Start()

Called when an application receives its first request. Generally used to initialize data that is shared among all users of an application.

Application_End()

Called when an application shuts down. Here you can write code to persist the information stored in memory that you want to have reloaded when the application restarts.

Session_Start()

Called when an ASP.NET application creates a new session for a user of the application.

Session_End()

Called when the user's session expires. By default, this happens 20 minutes after the last request of a page from a user.


Per-Request Events

The event handlers shown in Table 3.9 are invoked for each individual page request processed by the HttpApplication object.

Table 3.9 Per-Request Event Handlers

Event Handler

Purpose

Application_BeginRequest()

Called at the beginning of each request.

Application_AuthenticateRequest()

Called when a security module has established the identity of the user.

Application_AuthorizeRequest()

Called when a security module has verified user authorization.

Application_ResolveRequestCache()

Called to resolve the current request by providing content from a cache.

Application_AcquireRequestState()

Called to associate the current request with the session state.

Application_PreRequestHandlerExecute()

Called when ASP.NET begins executing a page.

Application_PostRequestHandlerExecute()

Called when ASP.NET finishes executing a page.

Application_ReleaseRequestState()

Called to save the current state data.

Application_UpdateRequestCache()

Called to update a cache with the responses.

Application_EndRequest()

Called at the end of each request.


As you can see from Table 3.9, you have complete control over how a request is processed. You can write code in any of these event handlers to modify the default behavior of ASP.NET. Step by Step 3.6 uses the Application_BeginRequest() and Application_EndRequest() methods to determine the time it took for each request to process and append this information with every response.

STEP BY STEP

3.6 Handling Global Events Using the global.asax File

  1. Open the global.asax file from the Solution Explorer. Click on the Click Here to Switch to Code View hyperlink to switch to code view.

  2. Add the following code to the Application_BeginRequest() event handler:

  3. protected void Application_BeginRequest(Object sender,
      EventArgs e)
    {
      // Store the begin time of the 
      // request in the HttpContext object
      this.Context.Items.Add("BeginTime", DateTime.Now);
    }
  4. Add the following code to the Application_EndRequest() event handler:

  5. protected void Application_EndRequest(Object sender,
      EventArgs e)
    {
       // Get the begin time from the HttpContext object
       DateTime dtBeginTime = 
       (DateTime) this.Context.Items["BeginTime"];
    
      // Calculate the time span between 
      // the start and end of request
      TimeSpan tsProcessingTime = 
        DateTime.Now-dtBeginTime;
    
      // Display the processing time taken 
      // by the response
      this.Context.Response.Output.Write("<hr>");
      this.Context.Response.Output.Write(
       "{0} took {1} milliseconds to execute.",
       this.Request.Url, 
       tsProcessingTime.TotalMilliseconds);
    }
  6. Run the project. You should see that the page shows a message at the bottom indicating the processing time of the request, as shown in Figure 3.7.

Figure 3.7 The global.asax file gives you access to application-level events that affect all the pages in an application.

In Step by Step 3.6, the Context object is used to store the begin time. The Context object exposes a key-value collection via the Items property in which you can add values that will be available for the life of the current request. The Context object gives access to the current HTTP request and response.

The modification of the global.asax file in Step by Step 3.6 will affect all other Web forms in the Web application 315C03. If at a later stage, you would like to disable the output generated by the global events, just comment the corresponding lines in the global.asax file.

REVIEW BREAK

State Management

Implement navigation for the user interface.

The value of the variables and controls collectively make up the state of a Web page. State management is the process of maintaining state for a Web page across roundtrips.

State management is ubiquitous with desktop-based applications, and programmers need not even care about it while developing these applications. However, because of the disconnected nature of the HTTP, state management is a big issue for Web applications.

ASP.NET provides several techniques for preserving state information across page postbacks. I'll broadly categorize these techniques as either client-side or server-side, depending on where the resources are consumed for state management.

Client-Side Techniques for State Management

Client-side techniques use the HTML code and the capabilities of the Web browser to store state-related information. ASP.NET supports the following techniques for storing state information at the client side:

Query Strings

Query strings are used to maintain state by appending the state information to a page's URL. The state data is separated from the actual URL with a question mark (?). The data attached to the URL is usually a set of key-value pairs, where each key-value pair is separated by an ampersand (&). For example, look at this URL that embeds two key-value pairs, name and city:

http://www.buddy.com/find.aspx?name=Bill+Gates&city=redmond

Because of its simplicity, query strings are widely used for passing a small amount of information to Web pages. However, query strings suffer the following limitations:

Reading information from query string in an ASP.NET program is easy using the QueryString property of the current HttpRequest object. QueryString returns a NameValueCollection object representing the key-value pairs stored in the query string. Step by Step 3.7 shows you how query strings can be used for client-side state management.

STEP BY STEP

3.7 Using Query Strings in a Web Application

  1. Add a new Web form to the project. Name the Web form StepByStep3_7.aspx. Change the pageLayout property of the DOCUMENT element to FlowLayout.

  2. Add two Label controls, two TextBox controls (txtName, txtEmail), and a Button control (btnSubmit) on the Web form.

  3. Double-click the button control and add the following code in the Click event handler:

  4. private void btnSubmit_Click(object sender, 
      System.EventArgs e)
    {
      // Redirect to StepByStep3_7a.aspx page,
      // with a query string containing name and 
      // email appended to the URL
      Response.Redirect("StepByStep3_7a.aspx?Name=" + 
        txtName.Text + "&Email=" + txtEmail.Text);
    }
  5. Add a new Web form to the project. Name the Web form StepByStep3_7a.aspx. Change the pageLayout property of the DOCUMENT element to FlowLayout.

  6. Add a Label control (lblInfo) to the Web form.

  7. Add the following code in the Page_Load() event handler:

  8. private void Page_Load(
      object sender, System.EventArgs e)
    {
      // If the query string collection contains Name
      if(Request.QueryString["Name"] != null)
      {
        // Display a message by getting Name and Email
        // from the query string collection
        lblInfo.Text = Request.QueryString["Name"] + 
          ", thanks for registering with us! ";
        lblInfo.Text += "You are subscribed at " + 
          Request.QueryString["Email"];
      }
    }
  9. Set StepByStep3_7.aspx as the start page in the project.

  10. Run the project. Enter a name and an email in the text boxes and click the Submit button. You should see that the button redirects the response to the StepByStep3_7a.aspx with the name and email address data in the query string. The new form then displays a message along with the name and email address fetched from the query string as shown in Figure 3.8.

Figure 3.8 The query string is used to maintain state by appending the state information to a page's URL.

If you observe the URL in Figure 3.8, you'll note that the name and email addresses are embedded in the URL itself. Query string is a very effective way to pass small non-sensitive pieces of information.

Cookies

Cookies are small packets of information—each storing a key-value pair at the client side. These packets are associated with a specific domain and are sent along with each request to the associated Web server.

A cookie can be set to expire when a user session ends, or you can request that the browser persist the cookie on the user's computer for a specified period. Cookies are commonly used to store users' preferences and provide them with a personalized browsing experience on their subsequent visits to a Web page.

Use of cookies suffers from the following limitations:

You can use the Cookies property of the HttpRequest object to get an HttpCookieCollection object that represents the cookies sent by the client for the current HTTP request.

Step by Step 3.8 shows you how cookies can be used for client-side state management.

STEP BY STEP

3.8 Using Cookies to Maintain Client-Side State

  1. Make a copy of the Web form StepByStep3_1.aspx and change its name to StepByStep3_8.aspx. Open the ASPX file and the CS file and replace all occurrences of StepByStep3_1 with StepByStep3_8.

  2. Switch to the code view and add the following code above the existing code in the Page_Load() event handler:

  3. private void Page_Load(
      object sender, System.EventArgs e)
    {
      if(Request.Cookies["Name"] == null)
      {
        // If the Name cookie does not exist,
        // ask user to enter name 
        Response.Redirect("StepByStep3_8a.aspx");
      }
      else
      {
        // If cookie already exists, show
        // a personalized welcome message to the user
        lblName.Text="Welcome " + 
         Request.Cookies["Name"].Value;
      }
    ...
    }
  4. Double-click the Post button control and add the following code in the Click event handler:

  5. private void btnPost_Click(
      object sender, System.EventArgs e)
    {
      // Format the data entered by the user and
      // use the name of the user stored in a cookie
      // Append to it the existing contents of lblWeblog
      lblWeblog.Text = "<b>" + 
          ddlCategories.SelectedItem.Text
          + " :: " + txtTitle.Text + ":: by "
          + Request.Cookies["Name"].Value + "</b> ("
          + DateTime.Now.ToString() + ")<hr>" 
          + txtMessage.Text + "<p>" 
          + lblWeblog.Text + "</p>";
    }
  6. Add a new Web form to the project. Name the Web form StepByStep3_8a.aspx. Change the pageLayout property of the DOCUMENT element to FlowLayout.

  7. Add a Label control, a TextBox control (txtName), a Button control (btnSubmit), and a CheckBox control (cbRemember) on the Web form.

  8. Double-click the Submit button control and add the following code in the Click event handler:

  9. private void btnSubmit_Click(object sender, 
      System.EventArgs e)
    {
      // Create a cookie called Name
      // Set the cookie with the Text of the text box
      HttpCookie cName = new HttpCookie("Name");
      cName.Value = txtName.Text;
      // Check if the checkbox remember me is checked
      if(cbRemember.Checked)
      {
        // Set the expiration time of the cookie
        // to 15 minutes from the current time
        cName.Expires = DateTime.Now + 
          new TimeSpan(0,0,15,0);
      }
      // Add the cookie to the response cookies 
      // collection to send it to the client's machine
      Response.Cookies.Add(cName);
      // Redirect the response to the message post page
      Response.Redirect("StepByStep3_8.aspx");
    }
  10. Set StepByStep3_8.aspx as the start page in the project.

  11. Run the project. You should see that you have been redirected to StepByStep3_8a.aspx. Enter a name, select the checkbox, and click the Submit button. You'll now see StepByStep3_8.aspx with a personalized greeting. Post a message. You should see that your name is now posted along with the title of the message, as shown in Figure 3.9.

  12. Figure 3.9 Cookies can be used to provide personalization settings for individual users.

  13. Close this browser window. Open another browser window and browse to StepByStep3_8.aspx. Assuming that you checked the Remember Me check box in step 8, you should see the Weblog window personalized with your name.

Step by Step 3.8 demonstrates how cookies can be used to persist state across browser restarts. If you don't select the check box, cookies will just be stored in the primary memory and will be destroyed when the browser window is closed. The program also demonstrates how you can request the browser to set an expiration date and time for the cookie. Step by Step 3.8 sets the expiration time of the cookie to 15 minutes from the current time. You should note that this is just a request; browsers are free to override this with their own settings.

Hidden Fields

Hidden fields contain information that is not visible on the page but is posted to the server along with a page postback. All modern browsers support hidden fields on a Web page. However, hidden fields have some limitations as mentioned in the following list:

ASP.NET provides an HTML server control, HtmlInputHidden, that maps to the <input type="hidden"> HTML element. Step by Step 3.9 demonstrates the use of hidden fields to maintain the number of posts on the Weblog page created in Step by Step 3.1.

STEP BY STEP

3.9 Using Hidden Fields to Maintain Client-Side State

  1. Make a copy of the Web form StepByStep3_1.aspx and change its name to StepByStep3_9.aspx. Open the ASPX file and the CS file and replace all occurrences of StepByStep3_1 with StepByStep3_9.

  2. Place a Label control (lblPosts) and an HTML Hidden control (txtPosts) next to the Post button control on the form.

  3. Switch to the code view and modify the Click event handler of the btnPost control as follows:

  4. private void btnPost_Click(object sender, 
      System.EventArgs e)
    {
      // Format the data entered by the user and
      // append it to the existing contents of lblWeblog
      lblWeblog.Text ="<b>" + 
           ddlCategories.SelectedItem.Text
           + " :: " + txtTitle.Text + "</b> (" 
           + DateTime.Now.ToString() + ")<hr>" 
           + txtMessage.Text + "<p>" 
           + lblWeblog.Text + "</p>";
    
      // As one more post is added 
      // Increment the value of the hidden control
      Int32 intPostCount = 
        Int32.Parse(txtPosts.Value) + 1;
      txtPosts.Value = intPostCount.ToString();
      lblPosts.Text = "Total Posts: (" + 
        txtPosts.Value + ")";
    
    }
  5. Set StepByStep3_9.aspx as the start page in the project.

  6. Run the project. Make a few entries in the Weblog. You will see that with each entry in the Weblog, the total posts value is increased by 1, as shown in Figure 3.10.

Figure 3.10 Contents of hidden fields are posted to the Web server with each page postback.

Step by Step 3.9 shows a typical example in which the hidden fields can be used to maintain state information. Here, because a hidden field is an input control, its value is posted back to the Web server with each page postback. The hidden fields can be used to store page scope values between roundtrips. The HtmlInputHidden control is not available as a Web server control mainly because ASP.NET uses a similar, but more powerful, technique called view state.

View State

View state is the mechanism that ASP.NET uses to maintain the state of controls across page postbacks. Just like hidden fields and cookies, you can also use view state to maintain state for non- control values in a page. However, it is important to note that the view state works only when a page is posted back to itself.

The following sections explain how view state works in various scenarios.

View State for Postback Controls

Some server controls, such as TextBox, CheckBox, and so on, post their values as part of the postback operation. These types of controls are also known as postback controls. For postback controls, ASP.NET retrieves their values one by one from the HTTP Request and copies them to the control values while creating the HTTP response. Traditionally, Web developers had to manually write this code for maintaining state for the postback controls, but now ASP.NET does this automatically.

View state does not require any additional storage either on the client side or on the server side for maintaining state for the postback controls.

View State for Non-postback Controls

In addition to the postback controls, the view state mechanism of ASP.NET also retains values for non-postback controls (that is, the controls that do not post their values as part of the postback operation, such as a Label control). You might wonder how ASP.NET manages to maintain values for a control even when the controls do not post their values. Actually, no magic is involved; ASP.NET extends the concept of hidden fields to accomplish this.

When ASP.NET executes a page, it collects the values of all non-postback controls that are modified in the code and formats them into a single, base64-encoded string. This string is then stored in a hidden field in a control named __VIEWSTATE, as in this example:

<input type="hidden" name="__VIEWSTATE" value=
"dDwtMTg3NjA4ODA2MDs7PoYLsizcOhkv2XeRfSJNPt12o1HP" />

The hidden input field is a postback control, so in the next postback of the page, the encoded string stored in the __VIEWSTATE field is also posted. At the Web server, ASP.NET decodes the view state string at page initialization and restores the controls values in the page.

Maintaining state using this technique does not require many server resources, but it definitely increases the size of the HTML file, which therefore increases the amount of time it takes to load the page.

View State for Page-Level Values

The ViewState property of the Page class is a great place to store page-level values. View state will save these values just prior to rendering the page and will restore the values at the time of page initialization after the postback operation. This might sound like cookies or hidden fields, but a major improvement is that you are not just limited to storing simple values. You can use the ViewState to store any object as long as it is serializable.

A good practice is to expose a page-level value as a property that internally manipulates the ViewState of the page. For example,

protected int NumberOfPosts
{
  get
  {
    if(ViewState["NumberOfPosts"] == null)
    {
      return 0;
    }
    else
    {
      return Convert.ToInt32(
        ViewState["NumberOfPosts"]);
    }
  }
  set
  {
    ViewState["NumberOfPosts"] = value;
  }
}

I'll use this technique in Step by Step 3.10 to maintain the number of posts on the Weblog using the view state.

STEP BY STEP

3.10 Using View State to Maintain State for Page-Level Values

  1. Make a copy of the Web form StepByStep3_1.aspx and change its name to StepByStep3_10.aspx. Open the ASPX file and the CS file and replace all occurrences of StepByStep3_1 with StepByStep3_10.

  2. Place a Label control (lblPosts) next to the button control on the form.

  3. Switch to the code view and add the following property to the class StepByStep3_10 definition:

  4. // get or set the number of posts in the Weblog
    protected int NumberOfPosts
    {
      get
      {
        if(ViewState["NumberOfPosts"] == null)
        {
          // The NumberOfPosts key is not
          // present in the ViewState
          return 0;
        }
        else
        {
          // Retrieve the NumberOfPosts key
          // from the ViewState
          return Convert.ToInt32(
              ViewState["NumberOfPosts"]);
        }
      }
      set
      {
        // Set the NumberOfPosts key in the ViewState
        ViewState["NumberOfPosts"] = value;
      }
    }
  5. Modify the event handler for the Click event of the btnPost control as shown here:

  6. private void btnPost_Click(
      object sender, System.EventArgs e)
    {
      // Format the data entered by the user and
      // append it to the existing contents of lblWeblog
      lblWeblog.Text = "<b>" + 
           ddlCategories.SelectedItem.Text
           + " :: " + txtTitle.Text + "</b> (" 
           + DateTime.Now.ToString() + ")<hr>" 
           + txtMessage.Text + "<p>" 
           + lblWeblog.Text + "</p>";
      // One more post is added 
      // Increment the value of NumberOfPosts
      // key in the Page's ViewState
      NumberOfPosts = NumberOfPosts + 1;
      lblPosts.Text = "Total Posts : (" + 
        NumberOfPosts + ")";
    }
  7. Set StepByStep3_10.aspx as the start page in the project.

  8. Run the project. Make a few entries in the Weblog. You should see that with each entry in the Weblog, the total posts value is increased by 1, just as it did in Step by Step 3.10.

  9. View the HTML code rendered in the Web browser. You'll note that the value associated with the __VIEWSTATE field increases as the size of the text in the lblWeblog control increases.

As you can see in Step by Step 3.10, view state is internally maintained as a hidden field. However, view state provides a higher degree of customizability and other security features that you'll see shortly.

Disabling View State

By default, view state is enabled in an ASP.NET application. As you have observed in Step by Step 3.10, the size of information stored in view state can increase the size of HTML for a Web page. This is especially important when your application contains complex controls such as a DataList or DataGrid. To optimize a Web page's size, you might want to disable view state in the following cases:

ASP.NET provides you complete flexibility to disable view state at various levels as mentioned in the following list:

Protecting View State

To prevent malicious users from manipulating the view state, ASP.NET provides a way of knowing if somebody has modified the contents of the view state to fool your application. Using this technique, the view state is encoded using a hash code (using the SHA1 or MD5 algorithms) when it is sent to the browser. When the page is posted back, ASP.NET checks the encoded view state to verify that it has not been tampered with on the client. This type of check is called a machine authentication check (MAC). By default, ASP.NET has the following entry in its machine.config file:

<pages EnableViewStateMac="true" />

ViewState Decoder

You can decode the contents stored in the __VIEWSTATE hidden input control using the ViewState Decoder utility written by Fritz Onion. You can download this utility from

http://www.develop.com/devresources/ resourcedetail.aspx?type=t&id=827

This enables tamper proofing for all applications running on a Web server. You can also manually enable or disable the tamper-proofing check at a page level by setting the EnableViewStateMac attribute of the Page directive to true or false in the ASPX page:

<%@ Page EnableViewStateMac="false"%>

Secure Only When Needed

Running security algorithms puts additional overhead on your Web server and makes applications slower. Therefore, you should enable security for view state only when it is a must.

However, this scheme just makes the view state tamper proof. It does not restrict the users from determining the contents of the view state. Although the values are not directly visible as in the cases of query strings or hidden variables, determined users can readily decode the view state.

View State Security on a Web Farm

When securing the view state for applications running on a Web farm configuration, you must use the same validation key for all the machines on a Web farm. To do this, use a manually assigned key instead of the default autogenerated key with the <machineKey> setting in the machine.config file.

With only a few configuration changes, it's possible to instruct ASP.NET to encrypt the contents of view state using Triple DES symmetric algorithm (3DES), making it extremely difficult for the clients to decode the view state. This kind of encryption can be applied only at the machine level by specifying the following setting in the machine.config file:

<machineKey validation='3DES' />

Choosing a Client-Side State Management Technique

Table 3.10 lists the advantages and disadvantages of the various client-side state management techniques. This table will help you make a quick decision about which client-side state management technique to choose in a given scenario.

Table 3.10 Comparing the Client-Side State Management Techniques

Technique

Advantage

Disadvantage

QueryString

Requires no postback operation.

Most browsers limit the length of data that can include in a query string.

 

 

No Security.

 

 

No options for persistence.

 

 

No support for storing structured values.

Cookies

State can be persisted on user's computer.

Some users disable cookies in their browsers.

 

Requires no postback operation.

Size restriction by browser (~4 to 8KB).

 

 

No support for storing structured values.

 

 

No Security.

Hidden fields

Can be used for pages that post to themselves or to other pages.

Increases HTML size.

 

 

No support for storing structured values.

 

 

No Security.

 

 

No options for persistence.

View State

Support for structured values.

Increases HTML size.

 

Involves less coding.

Works only when a page posts back to itself.

 

Easy configuration options for security.

No options for persistence.


Server-Side Techniques for State Management

Unlike client-side techniques for state management, server-side techniques use server resources for storing and managing state. One of the advantages of using server-side techniques for state management is that the possibility of a user spoofing or reading the session data is eliminated, but there is a disadvantage, too: These techniques use server resources, raising scalability issues.

ASP.NET supports server-side state management at two levels—at the level of the Web application using the application state, and at the level of a user session using the session state.

Session State

An ASP.NET application creates a session for each user who sends a request to the application. ASP.NET distinctly identifies each of these sessions by sending a unique SessionID to the requesting browser. This SessionID is sent as a cookie or is embedded in the URL, depending on the application's configuration.

This mechanism of sending SessionID ensures that when the next request is sent to the server, the server can use the unique SessionID to distinctly identify the repeat visit of the user. Both user visits are considered to belong to the same session.

The capability of uniquely identifying and relating requests can be used by Web developers to store session-specific data. A common example is storing the shopping cart contents for the users as they browse through the store. This session-specific information is collectively known as the session state of a Web application.

Comparing ASP.NET Session State with ASP

The concepts of SessionID and session state are not unique to ASP.NET. ASP.NET's predecessor, ASP, also supported these features. However, session state in ASP was considered a flaw and many large sites wrote their own code for maintaining session state. ASP.NET comes with a new implementation of session state that removes all the old problems and provides several enhancements that are equally useful to small and very large Web sites. Table 3.11 compares these improvements.

Table 3.11 Managing the Session State

The ASP Way

The ASP.NET Way

ASP maintains the state in the same process that hosts ASP. If the ASP process somehow fails, the session state is lost.

ASP.NET allows you to store session state out-of-process in a state service or database.

Each ASP Web server maintains its own session state. This creates a problem in the Web farm scenario, where the user's requests can be dynamically routed to different servers in the Web farm.

Because ASP.NET can store its session state out-of-process, several computers in a Web farm can use a common computer as their session state server.

ASP sessions do not work with browsers that don't support cookies or where the users have disabled cookies.

ASP.NET supports cookieless sessions by storing the SessionID in the URL itself by changing the application configuration.


Moreover, session state in ASP.NET is configurable. Depending on the requirements of your Web application, you can change the way the session state is maintained in your application by just changing a few lines in an XML-based configuration file (web.config). You will learn about session state configuration in Chapter 15.

Using Session State

ASP.NET uses an instance of the HttpSessionState class to provide access to the session data for the user who originated the request. In an ASPX page, this object is accessible through the Session property of the Page class. This property provides access to the HttpSessionState object that stores the session state as a collection of key-value pairs, where the key is of string type while the value can be any type derived from System.Object. Tables 3.12 and 3.13 explain properties and methods of the HttpSessionState class, respectively.

Table 3.12 Properties of the HttpSessionState Class

Property

Description

CodePage

Specifies the code page identifier for the current session. This provides compatibility with ASP. Response.ContentEncoding.CodePage should be used instead.

Contents

Gets a reference to the session state (HttpSessionState) object. This provides compatibility with ASP.

Count

Gets the number of objects in the session state.

IsCookieless

Indicates whether the session is managed using cookieless session.

IsNewSession

Indicates whether the session has been created with the current request.

IsReadOnly

Indicates whether the session is read-only.

IsSynchronized

Indicates whether access to the session state is synchronized (thread-safe).

Keys

Gets a collection of all session keys.

LCID

Specifies the locale identifier (LCID) of the current session.

Mode

Gets the current session state mode. The values are defined by the SessionStateMode enumeration—Off (disabled), InProc (default, session state is stored in process with aspnet_wp.exe), SqlServer (session state is stored in SQL Server), and StateServer (session state is stored in state service).

SessionID

Represents the unique session identifier used to identify a session.

StaticObjects

Gets a collection of objects declared by <object runat="server" scope="Session"> tags within the ASPX application file global.asax.

SyncRoot

Gets an object that can be used to synchronize access to the collection of session state values.

Timeout

Specifies the timeout period (in minutes) allowed between requests before the session state provider terminates the session.


Table 3.13 Methods of the HttpSessionState Class

Property

Description

Abandon

Cancels the current session.

Add

Adds a new object to the session state.

Clear

Removes all objects from the session state.

CopyTo

Copies the session state values to a single-dimensional array at the specified index.

GetEnumerator

Gets an enumerator of all session state values in the current session.

Remove

Removes an object from the session state.

RemoveAll

Removes all the objects from the session state. Calls the Clear() method internally.

RemoveAt

Removes an object from the session state at a particular index.


Step by Step 3.11 demonstrates the use of session state by upgrading the cookie example that you used in Step by Step 3.8 to maintain the session state at the server side instead of maintaining state at the client side.

STEP BY STEP

3.11 Using Session State

  1. Make a copy of the Web form StepByStep3_1.aspx and change its name to StepByStep3_11.aspx. Open the ASPX file and the CS file and change all occurrences of StepByStep3_1 with StepByStep3_11.

  2. Switch to code view and add the following code above the existing code in the Page_Load() event handler:

  3. private void Page_Load(
      object sender, System.EventArgs e)
    {
      if(Session["Name"] == null)
      {
        // The Name key is not present in the session
        // state, navigate to StepByStep3_11a page
        // to accept name of the user
        Response.Redirect("StepByStep3_11a.aspx");
      }
      else
      {
        // The Name key is present in the session
        // state, display a greeting
        lblName.Text="Welcome " + 
          Session["Name"].ToString();
      }
    ...
    }
  4. Double-click the Post button control and add the following code in the Click event handler:

  5. private void btnPost_Click(object sender, 
      System.EventArgs e)
    {
      // Format the data entered by the user and
      // append it to the existing contents of lblWeblog
      lblWeblog.Text = "<b>" +
         ddlCategories.SelectedItem.Text
        + " :: " + txtTitle.Text + ":: by "
        + Session["Name"].ToString() + "</b> ("   
        + DateTime.Now.ToString() + ")<hr>" 
        + txtMessage.Text + "<p>" 
        + lblWeblog.Text + "</p>";
    }
  6. Add a new Web form to the project. Name the Web form StepByStep3_11a.aspx. Change the pageLayout property of the DOCUMENT element to FlowLayout.

  7. Add a Label control, a TextBox control (txtName), and a Button control (btnSubmit) to the Web form.

  8. Double-click the Submit button control and add the following code in the Click event handler:

  9. private void btnSubmit_Click(object sender, 
      System.EventArgs e)
    {
      // Add the Name entered in the Session
      // Redirect the response to the Weblog page
      Session["Name"] = txtName.Text;
      Response.Redirect("StepByStep3_11.aspx");
    }
  10. Set StepByStep3_11.aspx as the start page in the project.

  11. Run the project. You will see that you have been redirected to StepByStep3_11a.aspx. Enter a name and click the Submit button. You'll now see the StepByStep3_11.aspx page with a personalized greeting. Post a message. You should see that your name is now posted along with the title of the message (refer to Figure 3.9).

  12. Close this browser window. Open another browser window and browse to StepByStep3_11.aspx. You should see that you have again been redirected to StepByStep3_11a.aspx to enter your name information.

Step by Step 3.11 demonstrates that session state is not persistently stored like cookies. The default technique of passing SessionID is with non-persistent cookies, so this example only works if you are using a cookie-enabled browser. If you instead want to use a cookieless session, you'll have to modify the web.config file associated with this application to set the cookieless attribute to true in the <sessionState> element:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.web>
    <sessionState mode="Inproc" 
       cookieless="true" />
  ...
  </system.Web>
</configuration>

Application State

Application state is used to store data that is globally used throughout the application. The application state is stored in memory, and unlike the session state, application state can't be configured for storage on another server or a SQL database. This limits the usefulness of the application state for Web farm scenarios.

Application state can be easily accessed through the Application property of the Page class. This property provides access to the HttpApplicationState object that stores the application state as a collection of key-value pairs, where the key is a string type, and the value can be any type derived from System.Object. Tables 3.14 and 3.15 discuss properties and methods of the HttpApplicationState class, respectively.

Table 3.14 Properties of the HttpApplicationState Class

Property

Description

AllKeys

Gets the collection of all key names in the application state as a string array.

Contents

Gets a reference to the application state (HttpApplicationState) object. This provides compatibility with ASP.

Count

Gets the number of objects in the application state.

Keys

Gets the NameObjectCollectionBase.KeysCollection collection of all the key names in the application state.

StaticObjects

Gets all objects declared via an <object runat="server" scope="Application"></object> tag within the ASP.NET application.


Table 3.15 Methods of the HttpApplicationState Class

Property

Description

Add

Adds a new object to the application state.

Clear

Removes all objects from the application state.

Get

Gets an object from the application state by key name or index.

GetKey

Gets a key from the application state by index.

Lock

Locks access to the application state object. This is used to prevent other clients from changing data stored in the application state.

Remove

Removes an object from the application state.

RemoveAll

Removes all the objects from the application state. Calls the Clear() method internally.

RemoveAt

Removes an object from the application state at a particular index.

Set

Updates the value of an object stored in the application state.

Unlock

Unlocks access to the application state.


Step by Step 3.12 demonstrates the use of Application property to store the application-wide data.

STEP BY STEP

3.12 Using the Application State

  1. Add a new Web form to the project. Name the Web form StepByStep3_12.aspx. Change the pageLayout property of the DOCUMENT element to FlowLayout.

  2. Switch to code view and add the following code in the Page_Load() event handler:

  3. private void Page_Load(
      object sender, System.EventArgs e)
    {
      // Lock the Application as the 
      // application state value needs to be modified
      Application.Lock();
      if(Application["HitCount"] != null)
      {
        // Increment the HitCount variable 
        // stored in the application state
        Application["HitCount"] = 
          (int) Application["HitCount"] + 1;
      }
      else
      {
        Application["HitCount"] = 1;
      }
      // Unlock the application as the changes are done
      Application.UnLock();
      // Display the hit count of this page by 
      // fetching the value from the HitCount key
      // in the application state
      lblInfo.Text = "This page has been accessed (" + 
       Application["HitCount"].ToString() + ") times!";
    }
  4. Set StepByStep3_12.aspx as the start page in the project.

  5. Run the project. You should see that the page shows the number of times it has been accessed. Refresh the page, and you should see that the page access counter increments by 1 as shown in Figure 3.11.

  6. Figure 3.11 Application state allows you to store global information.

  7. Close this browser window. Open another browser window and browse to StepByStep3_12.aspx. You should see that the page retains the value of the counter and increments it by 1.

Note that the technique used in Step by Step 3.12 is a volatile way to store the hit count (that is, users only see the total number of hits since the last time the application started). If you want the hit count to persist across application restarts, you should store the hit count periodically to a database.

In Step by Step 3.12, I modified the contents of application state using a pair of Application.Lock() and Application.UnLock() methods. Locking is important for keeping application state consistent when multiple users might want to modify the application object's content concurrently. While the application is locked, only the current user will be able to change the contents of the application state. This locking mechanism can severely reduce the scalability of a Web application; therefore, you should usually not store any updatable data in the application state.

No Locking Needed for Application_Start() and Application_End()

There is no need to use the Application.Lock() and Application.Unlock() methods in the Application_Start() and Application_End() event handlers because these event handlers are only called just once during the lifetime of an application.

Later in this book in Chapter 15, you'll learn about an alternative way of maintaining global state for an application using the application data cache. In fact, the application data cache provides everything that application state offers and provides several other advanced features, such as cache expiration policy. I recommend using application state only when you are migrating ASP applications to ASP.NET and want to write minimal code. In all other cases and for all new ASP.NET applications, you should use the application data cache as your preferred choice for storing global data.

REVIEW BREAK

Navigation Between Pages

Implement navigation for the user interface.

A typical Web application is a collection of Web pages linked to each other. In Chapter 2, I discussed the HyperLink control that allows a user to navigate to a different Web page when the hyperlink is clicked. However, there is also a need to navigate to a Web page programmatically. ASP.NET provides the following methods for programmatically navigating between pages:

I'll discuss each of these methods in the following sections.

The Response.Redirect() Method

The Response.Redirect() method causes the browser to connect to the specified URL. When the Response.Redirect() method is called, it creates a response whose header contains a 302 (Object Moved) status code and the target URL. When the browser receives this response from the server, it uses the header information to generate another request to the specified URL. When using the Response.Redirect() method, the redirection happens at the client side and involves two roundtrips to the server.

Using the Response.Redirect() method is recommended in the following cases:

The Server.Transfer() Method

The Server.Transfer() method transfers the execution from the current ASPX page to the specified ASPX page. The path specified to the ASPX page must be on the same Web server and must not contain a query string.

When the Server.Transfer() method is called from an executing ASPX page, the current ASPX page terminates execution and control is transferred to another ASPX page. The new ASPX page still uses the response stream created by the prior ASPX page. When this transfer occurs, the URL in the browser still shows the original page because the redirection occurs on the server side and the browser remains unaware of the transfer.

When you want to transfer control to an ASPX page residing on the same Web server, you should use Server.Transfer() instead of Response.Redirect() because Server.Transfer() will avoid an unnecessary roundtrip and provide better performance and user experience.

The default use of the Server.Transfer() method does not pass the form data and the query string of the original page request to the page receiving the transfer. However, you can preserve the form data and query string of the original page by passing a true value to the optional second argument, of the Server.Transfer() method. The second argument takes a Boolean value that indicates whether to preserve the form and query string collections.

When you set the second argument to true, you need to be aware of one thing: that the destination page contains the form and query string collections that were created by the original page. As a result, the hidden _VIEWSTATE field of the original page is also preserved in the form collection. The view state is page scoped and is valid for a particular page only. This causes the ASP.NET machine authentication check (MAC) to announce that the view state of the new page is tampered with. Therefore, when you choose to preserve the form and query string collections of the original page, you must set the EnableViewStateMac attribute of the Page directive to false for the destination page.

The Server.Execute() Method

The Server.Execute() method allows the current ASPX page to execute a specified ASPX page. The path to the specified ASPX page must be on the same Web server and must not contain a query string.

Bad HTML Code

The output returned to the browser by Server.Execute() and Server.Transfer() might contain multiple <html> and <body> tags because the response stream remains the same while executing another ASPX page. Therefore, the output that results from calling these methods might contain bad HTML code.

After the specified ASPX page is executed, control transfers back to the original page from which the Server.Execute() method was called. This technique of page navigation is analogous to making a method call to an ASPX page.

The called ASPX page has access to the form and query string collections of the calling page: Thus, for the reasons explained in the previous section, you need to set the EnableViewStateMac attribute of the Page directive to false on the called ASPX page.

By default, the output of the executed page is added to the current response stream. This method also has an overloaded version in which the output of the redirected page can be fetched in a TextWriter object instead of adding the output to the response stream. This helps you control where the output is placed on the original page.

STEP BY STEP

3.13 Using the Response.Redirect(), Server.Transfer(), and Server.Execute() Methods

  1. Add a new Web form to the project. Name the Web form StepByStep3_13.aspx. Change the pageLayout property of the DOCUMENT element to FlowLayout.

  2. Add three Label controls, a Literal control (litDynamic), two TextBox controls (txtRows, txtCells), and three Button controls (btnTransfer, btnExecute, and btnRedirect) to the Web form, as shown in Figure 3.12.

  3. Figure 3.12 The design of a form that allows you to specify rows and columns to create a table dynamically.

  4. Double-click the three Button controls to add an event handler to the Click event of each button. Add the following code in their event handlers:

  5. private void btnRedirect_Click(object sender, 
      System.EventArgs e)
    {
      // Calling Response.Redirect by passing
      // Rows and Cells values as query strings
      Response.Redirect("StepByStep3_13a.aspx?Rows="
        + txtRows.Text + "&Cells=" + txtCells.Text);
    }
    
    private void btnTransfer_Click(object sender, 
      System.EventArgs e)
    {
      // Writing into Response stream
      Response.Write(
        "The following table is generated " +
        "by StepByStep3_13a.aspx page:");
      // Calling the Server.Transfer method
      // with the second argument set to true 
      // to preserve the form and query string data
      Server.Transfer("StepByStep3_13a.aspx", true);
      // Control does not come back here
    }
    
    private void btnExecute_Click(object sender, 
      System.EventArgs e)
    {
      // Creating a StringWriter object
      StringWriter sw = new StringWriter();
      // Calling the Server.Execute method by 
      // passing a StringWriter object
      Server.Execute("StepByStep3_13a.aspx", sw);
      // Control comes back
      // Displaying the output in the StringWriter
      // object in a Literal control
      litDynamic.Text = sw.ToString();
    }
  6. Add a new Web form to the project. Name the Web form StepByStep3_13a.aspx. Change the pageLayout property of the DOCUMENT element to FlowLayout.

  7. Add a Table control (tblDynamic) from the Web Forms tab of the Toolbox to the Web form.

  8. Switch to the HTML view of the StepByStep3_13a.aspx file and modify the Page directive to add the EnableViewStateMac="false" attribute:

  9. <%@ Page language="c#" 
       Codebehind="StepByStep3_13a.aspx.cs" 
       AutoEventWireup="false" 
       Inherits="_315C03.StepByStep3_13a" 
       EnableViewStateMac="false" 
    %>
  10. Switch to code view and add the following method in the class definition:

  11. private void CreateTable(Int32 intRows, Int32 intCells)
    {
      // Create a new table 
      TableRow trRow;
      TableCell tcCell;
    
      // Iterate for the specified number of rows
      for (int intRow=1; intRow <= intRows; intRow ++)
      {
        // Create a row 
        trRow = new TableRow();
        if(intRow % 2 == 0)
        {
          trRow.BackColor = Color.LightBlue;
        }
        // Iterate for the specified number of columns
        for (int intCell=1; intCell <= intCells; 
           intCell++)
        {
          // Create a cell in the current row
          tcCell = new TableCell();
          tcCell.Text = "Cell (" + intRow + "," 
            + intCell + ")";
          trRow.Cells.Add(tcCell);
        }
        // Add the row to the table
        tblDynamic.Rows.Add(trRow);
      }
    }
  12. Add the following code in the Page_Load() event handler:

  13. private void Page_Load(
      object sender, System.EventArgs e)
    {
      if(Request.Form["txtRows"] != null)
      {
        // If the request contains form data then the
        // page is called from the Server.Transfer or 
        // Server.Execute methods from the 
        // StepByStep3_13.aspx page. Get the Rows and 
        // Cells values from the form collection and 
        // Create a table. 
        CreateTable(
          Int32.Parse(Request.Form["txtRows"]),
          Int32.Parse(Request.Form["txtCells"]));
      }
      else if(Request.QueryString["Rows"] != null)
      {
        // If the request contains query string data
        // that means the response is redirected from 
        // the StepByStep3_14.aspx page. Get the Rows
        // and Cells value from the query string and 
        // Create a table.
        Response.Write("StepByStep3_13a.aspx:");
        CreateTable(
          Int32.Parse(Request.QueryString["Rows"]),
          Int32.Parse(Request.QueryString["Cells"]));
      }
    }
  14. Set StepByStep3_13.aspx as the start page in the project.

  15. Run the project. Enter the number of rows and cells and click all three buttons one by one. When you click the Redirect button, the browser is redirected to StepByStep3_13a.aspx by passing the Rows and Cells values as the query string data as shown in Figure 3.13. When you click the Transfer button, the browser doesn't change the page name in the location bar, but the control gets transferred to the StepByStep3_13a.aspx page as shown in Figure 3.14. Finally, when you click the Execute button, the StepByStep3_13a.aspx page is executed and control comes back to the calling page, where the output of the Server.Execute() method is displayed as shown in Figure 3.15.

Figure 3.13 The Response.Redirect() method can be used to navigate to a URL that contains query strings.

Figure 3.14 The Server.Transfer() method is used to navigate to an ASPX page on the same server without causing an additional roundtrip.

Figure 3.15 The Server.Execute() method executes the specified ASPX page and returns the control back to the calling page.

In fact, it's a good idea to keep the second argument set to false when using the Server.Transfer() method. When you want to pass some values from one page to another in the current HTTP request, instead of using the form and query string collections, you should use the HttpContext object. The HttpContext object gives access to all the information about the current HTTP request. It exposes a key-value collection via the Items property in which you can add values that will be available for the life of the current request. The Page class contains a property called Context that provides access to the HttpContext object for the current request.

You can use two techniques to access the values of one page from another page in the current HTTP request using the HttpContext objects—HttpContext.Handler and HttpContext.Items. I have demonstrated these techniques in the Guided Practice Exercise 3.2 and in the Exercise 3.2, respectively.

Guided Practice Exercise 3.2

When using the Server.Transfer() method, for security reasons, you might not want to disable the machine authentication check for the view state of a page or for an application. How would you pass the state of one page to another in that case?

The Page class contains a property called Context that provides access to the HttpContext object for the current request. The Handler property of the HttpContext object provides the instance of the page that first received the HTTP request.

To use the HttpContext.Handler property in your code, you should take the following steps:

In this exercise, you are required to modify Step by Step 3.13 to use the HttpContext.Handler property to retrieve the properties of the first page in the second page. How would you make this modification?

You should try working through this problem on your own first. If you are stuck, or if you'd like to see one possible solution, follow these steps:

  1. Open the project 315C03. Add a new Web form GuidedPracticeExercise3_2 to the project. Change the pageLayout property of the DOCUMENT element to FlowLayout.

  2. Add three Label controls, two TextBox controls (txtRows, txtCells), and one button control (btnTransfer) on the Web form.

  3. Switch to the code view and add the following property definition in the class definition:

  4. // Declaring properties to expose
    // the number of Rows and Cells entered
    public Int32 Rows
    {
      get
      {
        return Int32.Parse(txtRows.Text);
      }
    }
    public Int32 Cells
    {
      get
      {
        return Int32.Parse(txtCells.Text);
      }
    }
  5. Double-click the Transfer button control and add the following code in the Click event handler:

  6. private void btnTransfer_Click(object sender, 
      System.EventArgs e)
    {
      // Writing into Response
      Response.Write(
        "The following table is generated " +
        "by GuidedPracticeExercise3_2a.aspx page:");
      // Calling the Server.Transfer method
      Server.Transfer("GuidedPracticeExercise3_2a.aspx");
      // Control does not come back here
    }
  7. Add a new Web form to the project. Name the Web form GuidedPracticeExercise3_2a.aspx. Change the pageLayout property of the DOCUMENT element to FlowLayout.

  8. Add a Table control (tblDynamic) from the Web Forms tab of the Toolbox to the Web form.

  9. Switch to code view and add the following code in the class definition to create an instance of the GuidedPracticeExercise3_2 page:

  10. // Declare a variable to store an instance of 
    // the GuidedPracticeExercise3_2 Web form
    public GuidedPracticeExercise3_2 pageExercise3_2;
  11. Add the following code in the Page_Load() event handler:

  12. private void Page_Load(
      object sender, System.EventArgs e)
    {
      if(!IsPostBack)
      {
        // Because its the same request context, 
        // get the reference to the 
        // GuidedPracticeExercise3_2 page
        // through the current request Context.
        // Get the Rows and Cells value from the 
        // GuidedPracticeExercise3_2 Web form's 
        // properties and Create a table.
        pageExercise3_2 = (GuidedPracticeExercise3_2)
          Context.Handler;
        CreateTable(pageExercise3_2.Rows, 
          pageExercise3_2.Cells);
      }
    }
  13. Switch to code view and add the following method in the class definition:

  14. private void CreateTable(Int32 intRows, Int32 intCells)
    {
      // Create a new table 
      TableRow trRow;
      TableCell tcCell;
    
      // Iterate for the specified number of rows
      for (int intRow=1; intRow <= intRows; intRow ++)
      {
        // Create a row 
        trRow = new TableRow();
        if(intRow % 2 == 0)
        {
          trRow.BackColor = Color.LightBlue;
        }
        // Iterate for the specified number of columns
        for (int intCell=1; intCell <= intCells; 
          intCell++)
        {
          // Create a cell in the current row
          tcCell = new TableCell();
          tcCell.Text = "Cell (" + intRow + "," 
            + intCell + ")";
          trRow.Cells.Add(tcCell);
        }
        // Add the row to the table
        tblDynamic.Rows.Add(trRow);
      }
    }
  15. Set GuidedPracticeExercise3_2.aspx as the start page in the project.

  16. Run the project. Enter the number of rows and cells and click the Transfer button. You should see that the browser doesn't changes the page name in the location bar, but the control gets transferred to the GuidedPracticeExercise3_2a.aspx page. The GuidedPracticeExercise3_2a.aspx page is able to access the Rows and Cells properties of the GuidedPracticeExercise3_2.aspx page via the HttpContext.Handler property.

If you have difficulty following this exercise, review the section "Navigation between Pages" earlier in this chapter and perform Step by Step 3.13. After doing this review, try this exercise again.

REVIEW BREAK

Chapter Summary

KEY TERMS

In this chapter, you learned how to deal with the disconnected nature of Web applications using the state management techniques provided by ASP.NET. In addition to the traditional client-side state management techniques like query strings, cookies, and hidden variables, ASP.NET provides a new technique called view state. When used carefully, view state can give great benefits; however, careless use of view state can significantly increase the download size of the rendered HTML file.

You also learned about various server-side state management techniques. In particular, ASP.NET provides great improvements over the session state of ASP. Session state in ASP.NET is highly configurable. With small configuration changes, you can support Web farms and cookieless sessions.

I also discussed various ASP.NET intrinsic objects that can be accessed using the properties of the Page class, such as Request, Response, Session, Application, and Server. You experimented with several properties and methods of these objects throughout this chapter.

I also discussed the Response.Redirect(), Server.Transfer(), and Server.Execute() methods for implementing navigation from one page to another, as well as the advantages and limitations of each of these methods.

Apply Your Knowledge

Exercises

3.1 Using Session State to Create a Shopping Cart

Online stores often use session state to maintain information about a user's shopping cart. This allows the site to keep track of users' selections as they explore the store rather than requiring the users to add all the items at the same time.

In this exercise, you'll use a similar technique to manage a shopping cart. To keep the emphasis on session state, you'll keep the catalog smaller than you'll generally find at most stores.

Estimated time: 20 minutes

  1. Create a new Visual C# ASP.NET Web Application project at the location http://localhost/315C03Exercises.

  2. Add a Web form to the project. Name it ShoppingPage.aspx.

  3. Add three Label controls, three Textbox controls (txtNK, txtCF, and txtHA) and three Button controls (btnNK, btnCF, and btnHA) in to the table on the Web form (see Figure 3.16).

  4. Switch to code view and add the following code to add selected items and their quantities to the session:

  5. // Add the selected item to 
    // the session state
    private void AddToSession(
      String strProduct, int intQty)
    {
      if(Session[strProduct] != null)
      {
        // If the product already exists, 
        // increase its quantity
        Session[strProduct] = (int) 
         Session[strProduct] + intQty;
      }
      else
      {
        Session[strProduct] = intQty;
      }
    }
  6. Double-click the three button controls and add the following code to their Click event handlers:

  7. private void btnNK_Click(
      object sender, System.EventArgs e)
    {
      // Add the selected item 
      // to the shopping cart
      AddToSession("NK", Int32.Parse(
        txtNK.Text));
      // Display shopping cart
      Server.Transfer("ShoppingCart.aspx");
    }
    
    private void btnCF_Click(
      object sender, System.EventArgs e)
    {
      // Add the selected item 
      // to the shopping cart 
      AddToSession("CF", 
        Int32.Parse(txtCF.Text));
      // Display shopping cart
      Server.Transfer("ShoppingCart.aspx");
    }
    
    private void btnHA_Click(
      object sender, System.EventArgs e)
    {
      // Add the selected item 
      // to the shopping cart 
      AddToSession("HA", 
        Int32.Parse(txtHA.Text));
      // Display shopping cart
      Server.Transfer("ShoppingCart.aspx");
    }
  8. Add a new Web form to the project. Name the Web form ShoppingCart.aspx.

  9. Drag a Hyperlink control (hlShopping) to the Web form. Set its NavigateUrl property to ShoppingPage.aspx.

  10. Switch to code view and add the following code in the Page_Load() event handler:

  11. private void Page_Load(
      object sender, System.EventArgs e)
    {
      Response.Write(
       "The shopping cart contains" +
       " the following items: <br>");
      // Display the contents of 
      // the shopping cart
      for(int intI=0; intI < Session.Count; 
        intI++)
      {
        switch (Session.Keys[intI])
        {
          case "NK":
            Response.Write(
              "Nestle KitKat (" +
              Session[intI]+ ")" +
              "<br>");
            break;
          case "CF":
            Response.Write(
              "Cadbury's Fingers (" +
              Session[intI]+ ")"+ 
              "<br>");
            break;
          case "HA":
            Response.Write(
              "Hersheys Almonds (" + 
              Session[intI] + ")" +
              "<br>");
            break;
        }
      }
    }
  12. Set ShoppingPage.aspx as the start page in the project.

  13. Run the project. You'll see a shopping page as shown in Figure 3.16. Enter a quantity for a product and click on the Add to Cart button. You'll be taken to the shopping cart as shown in Figure 3.17. Add a few more items to the cart; you'll note that the shopping cart remembers your selections.

Figure 3.16 The Add to Cart button updates the session state with the corresponding item and its quantity.

Figure 3.17 The shopping cart page summarizes the user's selections by retrieving the information from the session state.

3.2 Creating a Wizard-like User Interface

When creating a wizard-like user interface, you need to access the information entered in one page from another page in the wizard.

When you use the Server.Transfer() method to navigate from one page to another, both the pages share the same HTTP context. From the first page, you can add items to the HTTP context and then retrieve these items in the second page.

The HttpContext object gives access to all the information about the current HTTP request. It exposes a key-value collection via the Items property in which you can add values that will be available for the life of the current request.

In this exercise, I'll show you how to use the Items property of the HttpContext object to retrieve values from previous page of a wizard.

Estimated time: 20 minutes

  1. Add a Web form to the project. Name it Magazine1.aspx.

  2. Drag two Label controls, a TextBox control (txtCode), and a Button control (btnCode) on the Web form. (see Figure 3.18).

  3. Figure 3.18 The first page of the wizard publishes its properties to the other page by adding it to a key-value collection via the HttpContext.Items property.

  4. Switch to the code view of the form. Add the following code in the class definition:

  5. // Declaring Code property to expose
    // the txtCode control's value
    public String Code
    {
      get
      {
        return txtCode.Text;
      }
    }
  6. Double-click the Next button control and add the following code in the Click event handler:

  7. private void btnNext_Click(
      object sender, System.EventArgs e)
    {
      // Adding the Code to the Items 
      // collection of the HttpContext
      // object for the current request
      Context.Items.Add("Code", txtCode.Text);
      // Calling the Server.Transfer method
      Server.Transfer("Magazine2.aspx");
    }
  8. Add another Web form to the project. Name it Magazine2.aspx.

  9. Drag two Label controls, two TextBox controls (txtName and txtAddress), and a Button control (btnCode) to the Web form (see Figure 3.19).

  10. Add the following code in the Page_Load() event handler:

  11. private void Page_Load(
      object sender, System.EventArgs e)
    {
      if(!IsPostBack)
      {
        // Fetch the Code value from the 
        // HttpContext object of the 
        // current request
        string strCode = 
         Context.Items["Code"].ToString();
        lblCode.Text = 
         "Priority Code: " + strCode;
      }
    }
  12. Set Magazine1.aspx as the start page of the project.

  13. Run the project. You will see the first page of the wizard as shown in Figure 3.18. Enter some text in the text box and click the Next button. You can see that the second page can retrieve the information entered in the first page of the wizard (see Figure 3.19) .

Figure 3.19 The second page of the wizard fetches the value of first page in the wizard through a key-value collection via the HttpContext.Items property.

Review Questions

  1. What is a postback? How can you determine when a postback occurs in an ASP.NET page?

  2. What file do you use to handle Session and Application level events?

  3. What are the classes mapped to the Response, Request, Server, Application, and Session properties of the Page class?

  4. What are the client-side techniques available for state management?

  5. What are the benefits of using view state in ASP.NET?

  6. What is the significance of setting the EnableViewStateMac property to true?

  7. What is the difference between the client-side and the server-side state management techniques?

  8. What type(s) of data can be stored in a session state and in an application state?

  9. When would you store an object in the session state instead of the application state?

  10. What methods can be called to perform server-side redirection to an ASPX page?

Exam Questions

  1. You are developing a Web form to display weather information. On the initial requests to the Web form, you need to do some initialization that will change the appearance of the form and assign values to some controls. However, this initialization should not be repeated again when the user submits the Web form. How should you write the code to accomplish this? (Select two)

    1. Write the code inside the Page_Init() event handler.

    2. Write the code inside the Page_Load() event handler.

    3. Execute the initialization code only when the Page.IsPostBack property is true.

    4. Execute the initialization code only when the Page.IsPostBack property is false.

  2. You have used ASP.NET to develop an inventory management system for your organization. Associates can access this application from the company's intranet. When analyzing users' feedback on the applications, you found that users complain that they receive an annoying flash when they submit forms. They also complain that the data entry form does not always remember the active controls and because of this, users have to press the Tab key several times before they can focus again on the desired control. This makes the data entry inconvenient and time- consuming. On analyzing further usage data, you found that all the users in your company use Internet Explorer 5.0 or above to access your application. What should you do to eliminate the problems reported by the users?

    1. Set SmartNavigation attribute of the Page directive to true.

    2. Set AutoEventWireup attribute of the Page directive to true.

    3. Set EnableViewState attribute of the Page directive to true.

    4. Set ClientTarget attribute of the Page directive to "ie5".

  3. You are developing an ASP.NET Web site for a popular Web development magazine. You want to keep track of how many times each page of your Web application is accessed. This data will help your company to analyze the usage pattern and develop most appropriate content. You want to write minimum code to achieve this task; which of the following techniques will you use?

    1. Use the Page_Load() event handler to increment the usage counter of the page.

    2. Use the Application_BeginRequest() event handler to increment the usage counter of the page.

    3. Use the Session_Start() event handler to increment the usage counter of the page.

    4. Use the Application_Start() event handler to increment the usage counter of the page.

  4. You are designing a Web application for a multinational company. When users access the Web site, you want them to be automatically redirected to a page specific to their country. Your colleague has developed a method that determines the user's country from the HTTP Request and does the redirection. Where should you call this method in your application?

    1. The Session_Start() event handler of the global.asax file

    2. The Begin_Request() event handler of the global.asax file

    3. The Page_Load() event handler of the default.aspx file

    4. The Application_Start() event handler of the global.asax file

  5. Your ASP.NET page contains a page-level variable of ArrayList type. You want to preserve the value of this variable across page postbacks. You do not need this variable in any other page in the application. Which of the following state management techniques provides the best way to achieve this?

    1. Query strings

    2. Cookies

    3. Session

    4. View state

  6. You are developing a Web application for an online bank. Your application allows users to access their account information and transactions right from their desktops. When the user logs on to your application, you want to show the username and current balance on all the pages of the application until the user logs off. You want your application to be safe from malicious users. Which of the following state management techniques should you use? (Select the best answer.)

    1. Cookies

    2. View state

    3. View state with encryption

    4. Session

  7. You are developing an online retail store using ASP.NET. Users can freely access the catalogs and add items to their shopping carts. Users are only required to log on to the Web site when they are ready to check out. However, you want to remember each user's name and greet the users on their future visits to the retail store. Which of the following state management techniques helps you accomplish this? (Select the best answer.)

    1. Hidden fields

    2. View state

    3. Cookies

    4. Session

  8. You have developed and deployed a Web application for an online bank. This application allows users to access their account information and transactions right from their desktops. Because the application deals with financial data, you have enabled encryption for the view state of all the pages. The bank business has rapidly increased, and the management has decided to upgrade the single Web server to a Web farm of Web servers. When you were testing the application for the Web farm, sometimes the application worked fine while other times it generated a view state error. What should you do to resolve this problem?

    1. Use the same validation key for all the Web servers in a Web farm.

    2. Use different validation keys for all the Web servers in a Web farm.

    3. Set the EnableViewStateMac attribute to true for all the pages in the application.

    4. Set the EnableViewStateMac attribute to false for all the pages in the application.

  9. You have recently developed and deployed a Web application for a large automotive parts supplier. This application is used by users from the United States, Europe, and Asia. You have received complaints from several users that the Web pages take very long to download. You did some research and found out that an HTML element named __VIEWSTATE in your pages is storing a large amount of data and is responsible for bigger page sizes. Your manager recommended that you to disable view state wherever it is not needed in the application. In which of the following cases would you like to disable view state in your application? (Select all that apply)

    1. Those pages that do not postback.

    2. Those pages that postback.

    3. Those controls that are not dynamically changed.

    4. Those controls that are dynamically changed.

    5. Those controls that are modified at every page load.

    6. Those controls that are not modified at every page load.

  10. You have recently developed and deployed a Web application for a large automotive parts supplier. This application is used by users from the United States, Europe, and Asia. You have received complaints from several users that the Web pages take very long to download. You did some research and found that an HTML element named __VIEWSTATE in your pages is storing a large amount of data and is responsible for bigger page sizes. You have also found that some of your pages do not use view state. You want to do minimum modification to the code. How would you disable view state for such pages?

    1. Set the EnableViewState property for all the Web server controls to false.

    2. Set the EnableViewState attribute of the Page directive to false.

    3. Set the EnableViewStateMac attribute of the Page directive to false.

    4. Set the EnableViewState attribute to false for the <Pages> element in the web.config file.

  11. In a Web page of your application, you allow users to select a product and its quantity. When the user has made her selection, you want to transfer the user to another page named "ShoppingCart.aspx" with the ProductId and Quantity as the query string parameters to the ASPX page. Which of the following methods would you use in your code to accomplish this?

    1. A HyperLink control

    2. The Response.Redirect() method

    3. The Server.Transfer() method

    4. The Server.Execute() method

  12. You are using a DataGrid control in a Web form "ShowData.aspx" of your Web application. You want to invoke another ASP.NET page, "GetData.aspx," that returns the data to be displayed in the DataGrid control. Which of the following methods would you use to invoke "GetData.aspx" from "ShowData.aspx"?

    1. A HyperLink control

    2. The Response.Redirect() method

    3. The Server.Transfer() method

    4. The Server.Execute() method

  13. You are developing an online bill payment system using ASP.NET. When a user logs on to the application by entering her username and password, you want to programmatically redirect the user to a page named "accountdetails.aspx" in the same Web application. You want an application that responds quickly to the users. Which of the following methods would you use to accomplish this?

    1. A HyperLink control

    2. The Response.Redirect() method

    3. The Server.Transfer() method

    4. The Server.Execute() method

  14. You are using a DataGrid control in an ASP.NET page ("ShowData.aspx") of your Web application. You want to invoke another ASP.NET page, "GetData.aspx," that returns the data to be displayed in the DataGrid control. You are using the Server.Execute() method to invoke "GetData.aspx" from the "ShowData.aspx" page. When you run the application, you get an Invalid View state error. Which of the following options would you choose to resolve this error?

    1. Use the Server.Transfer() method instead of the Server.Execute() method.

    2. Set the EnableViewStateMac attribute to false in the Page directive of "GetData.aspx."

    3. Set the EnableViewStateMac attribute to false in the Page directive of "ShowData.aspx."

    4. Set the EnableViewState attribute to false in the Page directive of "GetData.aspx."

  15. You are creating a Web site that allows users to create online communities to interact with their friends and families. The creation of a community requires the user to register with the Web site. You have created a User Registration Wizard that allows users to enter registration information in a step by step manner. The Wizard consists of two ASPX pages. You want all the data entered by the user in the first ASPX page to be available in the second page. For security reasons, you are not allowed to disable the view state machine authentication check in your ASP.NET pages. Which of the following options would you use? (Select two)

    1. For each screen, add the collected data to the Context.Items collection and retrieve the information from this collection in the last ASPX page.

    2. Use the Request.Form collection in the last ASPX page to retrieve the information entered by the user.

    3. Use the Server.Transfer() method to transfer the control from one wizard page to the next wizard page.

    4. Use the Server.Execute() method to transfer the control from one wizard page to the next wizard page.

Answers to Review Questions

  1. When a user submits the form to the Web server, it is called as a postback. The Page.IsPostBack property, when true, indicates that the page is loaded as a result of postback from the client.

  2. The ASP.NET application file, global.asax, contains event handlers to handle Session and Application level events.

  3. The classes that map to the Response, Request, Server, Application, and Session properties of the Page class are HttpResponse, HttpRequest, HttpServerUtility, HttpApplicationState, and HttpSessionState, respectively.

  4. You can use query strings, cookies, hidden fields, and view state for managing state at the client side.

  5. View state provides the following benefits:

  6. The EnableViewStateMac property, when set to true, performs a machine authentication check (MAC) on the view state during postback to verify that the view state has not been tampered with at the client side.

  7. The client-side state management techniques consume client resources to manage state, whereas the server-side techniques consume server resources to manage state.

  8. Any object that inherits from System.Object, directly or indirectly by chain of its inheritance, can be stored in session state and application state.

  9. When you need to store data that does not apply to all the users of the application but only to specific users, you should choose session state instead of the application state.

  10. Server.Transfer() and Server.Execute() methods can perform server-side redirection to an ASPX page.

Answers to Exam Questions

  1. B and D. The code for the initialization of controls should be placed inside the Page_Load() event handler. If you want to execute the initialization code only when the page is first requested and do not want to run that code again at the time of page postback, you must execute the code when the IsPostBack property of the Page class is false. For more information, see the section "The IsPostBack Property" in this chapter.

  2. A. When all users are using Internet Explorer versions 5.0 or later, you can set the SmartNavigation property to true. This will eliminate the flash and will cause Internet Explorer to focus active control. For more information, see the section "The SmartNavigation Property" in this chapter.

  3. B. Options C and D do not work with each page request, so only options A and B are viable choices. Between these two choices, you should choose to write the code in the Application_BeginRequest() event handler of the global.asax file because if you use the Page_Load() event handler, you'll have to write code in each and every ASPX page in the application. For more information, see the section "ASP.NET Application" in this chapter.

  4. A. When a user visits the site, the browser establishes a new session with the Web server. At that time, the Session_Start() event handler is executed. This method is executed only once for the user session and is an appropriate choice for the case in question. Page_Load() event handler might not work in all cases because the user could enter the Web site through a page other than default.aspx. Begin_Request() works for the entire HTTP request and not just the first request. The Application_Start() method will only redirect the first user of the application. For more information, see the section "ASP.NET Application" in this chapter.

  5. D. Because the variable is only required on a single page, you might not want to consume server resources by storing the values in session. You can instead use a client-side technique for state management, but cookies and hidden fields do not allow you to stored structured data. Therefore, the best option is to use view state. For more information, see the section "State Management" in this chapter.

  6. D. Cookies can be easily accessed and used by malicious users. View state with encryption does provide a high level of encryption but is only available on the same page. In the application, you want the name and current balance to be displayed on all the pages, so the correct choice is session. Session data is stored at the server side and cannot be easily tampered with. For more information, see the section "State Management" in this chapter.

  7. C. You want the information to be available across browser restarts. In this case, cookies are the right choice because they allow you to store a small amount of information on the user's computer. For more information, see the section "Client-side Techniques for State Management" in this chapter.

  8. A. When you use view state encryption in a Web farm, you must use the same validation key for all the Web servers. If the validation keys don't match, you will get an error when the user is directed to a different server in the Web farm. For more information, see the section "View State" in this chapter.

  9. A, C, and E. If the pages don't postback to themselves, they are not making use of view state; in that case, it's a good idea to disable view state for the whole page. For all other pages, the controls that are not dynamically changed need not have their view state enabled. Also, the controls whose values are modified on every page load need not store their values in the view state. For more information, see the section "View State" in this chapter.

  10. B. Setting the EnableViewState property for all the Web server controls to false does the trick but involves a lot of coding. An option that requires less code is to set the EnableViewState attribute of the Page directive to false. Changing EnableViewState to false in the web.config file will affect all the pages in the Web application—not just the one that uses view state—and is not recommended in the given case. For more information, see the section "View State" in this chapter.

  11. B. You cannot use query strings with the Server.Transfer() and Server.Execute() methods. The Hyperlink control does accept query strings, but the redirection needs to be performed within code. Therefore, the only choice that works is the use of Response.Redirect() method. For more information, see the section "Navigation Between Pages" in this chapter.

  12. D. Only the Server.Execute() method works like a method call. That is, it invokes the specified page and returns the control back to the original page. For more information, see the section "The Server.Execute() Method" in this chapter.

  13. C. Response.Redirect() involves an additional roundtrip and therefore is not a good option when you want the application to be faster. You should instead use the Server.Transfer() method to redirect your user to another ASPX page on the same Web server. For more information, see the section "The Server.Transfer() Method" in this chapter.

  14. B. You get an error while executing the Server.Execute() method because the view state of the "ShowData.aspx" page is passed to the "GetData.aspx" page along with the form and query string collections, causing the ASP.NET machine authentication check to fail. You need to set the EnableViewState attribute of the Page directive in the "GetData.aspx" page to false in order to resolve this error. For more information, see the section "Navigation Between Pages" in this chapter.

  15. A and C. You should choose Server.Transfer() and Context.Items to accumulate data from the previous page over the Server.Execute() and Request.Form methods because you cannot disable the view state machine authentication check and thus cannot preserve the form data. For more information, see the section "Navigation Between Pages" in this chapter.

Suggested Readings and Resources

  1. The Visual Studio .NET Combined Help Collection, including the following:

  2. ASP.NET/Visual Studio .NET Tips. http://www.swarren.net

  3. Fritz Onion. Essential ASP.NET. Addison-Wesley, 2002

  4. Jeff Prosise. Programming Microsoft .NET. Microsoft Press, 2002

 

800 East 96th Street, Indianapolis, Indiana 46240

sale-70-410-exam    | Exam-200-125-pdf    | we-sale-70-410-exam    | hot-sale-70-410-exam    | Latest-exam-700-603-Dumps    | Dumps-98-363-exams-date    | Certs-200-125-date    | Dumps-300-075-exams-date    | hot-sale-book-C8010-726-book    | Hot-Sale-200-310-Exam    | Exam-Description-200-310-dumps?    | hot-sale-book-200-125-book    | Latest-Updated-300-209-Exam    | Dumps-210-260-exams-date    | Download-200-125-Exam-PDF    | Exam-Description-300-101-dumps    | Certs-300-101-date    | Hot-Sale-300-075-Exam    | Latest-exam-200-125-Dumps    | Exam-Description-200-125-dumps    | Latest-Updated-300-075-Exam    | hot-sale-book-210-260-book    | Dumps-200-901-exams-date    | Certs-200-901-date    | Latest-exam-1Z0-062-Dumps    | Hot-Sale-1Z0-062-Exam    | Certs-CSSLP-date    | 100%-Pass-70-383-Exams    | Latest-JN0-360-real-exam-questions    | 100%-Pass-4A0-100-Real-Exam-Questions    | Dumps-300-135-exams-date    | Passed-200-105-Tech-Exams    | Latest-Updated-200-310-Exam    | Download-300-070-Exam-PDF    | Hot-Sale-JN0-360-Exam    | 100%-Pass-JN0-360-Exams    | 100%-Pass-JN0-360-Real-Exam-Questions    | Dumps-JN0-360-exams-date    | Exam-Description-1Z0-876-dumps    | Latest-exam-1Z0-876-Dumps    | Dumps-HPE0-Y53-exams-date    | 2017-Latest-HPE0-Y53-Exam    | 100%-Pass-HPE0-Y53-Real-Exam-Questions    | Pass-4A0-100-Exam    | Latest-4A0-100-Questions    | Dumps-98-365-exams-date    | 2017-Latest-98-365-Exam    | 100%-Pass-VCS-254-Exams    | 2017-Latest-VCS-273-Exam    | Dumps-200-355-exams-date    | 2017-Latest-300-320-Exam    | Pass-300-101-Exam    | 100%-Pass-300-115-Exams    |
http://www.portvapes.co.uk/    | http://www.portvapes.co.uk/    |