State Management

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 round trips.

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 an important 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 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

  • Cookies

  • Hidden fields

  • View state

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, in which each key-value pair is separated by an ampersand ( & ). For example, look at this URL that embeds two key-value pairs ( name and city):

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

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

  • Most browsers restrict the length of the query string; this reduces the amount of data you can embed in a URL.

  • Query strings do not provide any support for structured data types.

  • The information stored in a query string is not secure because it is directly visible to the user in the browser's address field.

Reading information from query strings in an ASP.NET program is easy using the QueryString property of the current HttpRequest object. The QueryString property returns a NameValueCollection object representing the key-value pairs stored in the query string. For example, the following expressions retrieve the value of the name and city, respectively, from the query string used in the previous URL:

 Request.QueryString["name"] Request.QueryString["city"] 
Cookies

Cookies are small packets of informationeach 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. 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:

  • Most browsers limit the size of information you can store in a cookie. The typical size is 4,096 bytes with older browser versions and 8,192 bytes with newer browser versions.

  • Some users configure their browsers to refuse cookies.

  • When you request that the browser persist a cookie on a user's computer for a specified period, the browser might override that request by using its own rules for cookie expiration.

  • Because cookies are stored at the client, they might be tampered with. You cannot trust data you receive from a cookie.

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. The following code segment shows how to set a cookie on a user's computer:

 // Create a cookie called Name HttpCookie cName = new HttpCookie("Name"); cName.Value = txtName.Text; // 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); 

To retrieve the value of a cookie, you just need to retrieve it from the HTTP request, as shown in the following code sample:

 if(Request.Cookies["Name"] == null) {    // the Name cookie does not exist, } else {    // the Name cookie exists    Response.Write(Request.Cookies["Name"].Value); } 
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 the following limitations:

  • Although information stored in a hidden field is not visible on the page, it is still part of the page's HTML code and users can see the value of a hidden field by viewing the HTML source of the page. Hidden fields are therefore not a good choice for storing information you want to keep secure.

  • Hidden fields are part of the page HTML. If you store more information in hidden fields, it increases the size of the HTML page, making it slow for users to download.

  • Hidden fields allow you to store only a single value in a field. If you want to store structured values such as those in a customer record, you must use several hidden fields.

ASP.NET provides an HTML server control, HtmlInputHidden , that maps to the <input type="hidden"> HTML element. 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 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 noncontrol values in a page. However, it is important to note that 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 for Nonpostback Controls

In addition to the postback controls, the view state mechanism of ASP.NET also retains values for nonpostback 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 nonpostback 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 control's values in the page.

Maintaining state using this technique does not require many server resources, but it does increase 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 saves these values just prior to rendering the page and restores 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.

The following example demonstrates how to use the view state to maintain state for page-level values, such as the number of posts on a Weblog:

  1. Add a new Visual C# ASP.NET Web Application project to the solution; name it Example4_3 .

  2. Delete the WebForm1.aspx file. Copy WebForm1.aspx from the Example4_1 project to the current project. Then open the ASPX file and the CS file and replace all occurrences of Example4_1 with Example4_3 . Place a Label control ( lblPosts ) next to the button control on the form.

  3. Switch to Code view and add the following property to the class definition for WebForm1 :

     // 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;     } } 
  4. Modify the event handler for the Click event of the btnPost control as shown here:

     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     lblPosts.Text = "Total Posts : (" + ++NumberOfPosts + ")"; } 
  5. 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.

  6. 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 the previous example, 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 the previous example, the size of information stored in view state can increase the size of the HTML for a Web page. ASP.NET provides complete flexibility in disabling view state at various levels:

  • At the level of a control If you populate the control's state on each request, you can disable view state at the control level by setting the EnableViewState property of the control to false :

     <asp:DataGrid EnableViewState="false" .../> 
  • At the level of a page If the page doesn't post back to itself, you can disable view state at the page level by setting the EnableViewState attribute of the Page directive to false in the ASPX page:

     <%@ Page EnableViewState="false" %> 
  • At the level of an application If none of the pages in an application post back to themselves , you can disable view state at the application level by adding the following line to the web.config file:

     <pages enableViewState="false"/> 
  • At the level of the machine In the unlikely case in which you want to disable view state for all applications running on a Web server, you can do so by adding the following statement to the machine.config file:

     <pages enableViewState="false"/> 
Protecting View State

ASP.NET provides a way of knowing whether somebody has modified the contents of the view state to fool your application. With 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" /> 

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

 <%@ Page EnableViewStateMac="false"%> 

However, this scheme just makes the view state tamper proof; it does not restrict 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 easily decode the view state.

With only a few configuration changes, you can instruct ASP.NET to encrypt the contents of the view state using the 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' /> 
graphics/tip_icon.gif

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 the farm. To do this, use a manually assigned key instead of the default autogenerated key with the <machineKey> setting in the machine.config file.


Choosing a Client-side State Management Technique

Table 4.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 4.10. Comparing the Client-side State Management Techniques

Technique

Advantage

Disadvantage

Query string

Requires no postback operation.

Most browsers limit the length of data that can be included 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.

Size restriction by browser operation.

Some users disable cookies in their browsers.

Requires no postback (approx. 4KB8KB).

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.

Involves less coding.

Easy configuration options for security.

Increases HTML size.

Works only when a page posts back to itself.

No options for persistence.

Server-side Techniques for State Management

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. However, there is a disadvantage, too: These techniques use server resources, raising scalability issues.

ASP.NET supports server-side state management at two levelsat 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 a 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 shopping cart contents for users as they browse through the store. This session-specific information is collectively known as the session state of the Web application.

Comparing ASP.NET Session State with ASP

ASP.NET comes with a new implementation of session state that removes all the old problems associated with ASP. Table 4.11 compares these improvements.

Table 4.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 on which 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 learn about session state configuration in Chapter 16, "Configuring a Web Application."

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, in which the key is of string type while the value can be any type derived from System.Object . Tables 4.12 and 4.13 explain the properties and methods of the HttpSessionState class, respectively.

Table 4.12. Properties of the HttpSessionState Class

Property

Description

CodePage

Specifies the codepage 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 a 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 read-only (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

Returns an HttpStaticObjectsCollection object that contains the objects declared by <object runat ="server" scope="Session"> tags within the ASP.NET application file global.asax .

SyncRoot

Returns 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 4.13. Methods of the HttpSessionState Class

Method

Description

Abandon()

Cancels the current session.

Add()

Adds the given object identified with the given name to the session state.

Clear()

Removes all objects from the session state.

CopyTo()

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

GetEnumerator()

Returns an enumerator object for the session state values in the current session.

Remove()

Removes an object from the session state.

RemoveAll()

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

RemoveAt()

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

The following example upgrades the Weblog example to maintain the session state at the server side:

  1. Add a new Visual C# ASP.NET Web Application project to the solution and name it Example4_4 .

  2. Delete the WebForm1.aspx file; then copy WebForm1.aspx from the Example4_1 project to the current project. Open the ASPX file and the CS file and change all occurrences of Example4_1 to Example4_4 . Place a new Label Web server control ( lblName ) just above the Category drop-down list.

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

     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 WebForm2 to accept name of the user         Response.Redirect("WebForm2.aspx");     }     else     {         // The Name key is present in the session state         lblName.Text="Welcome " + Session["Name"].ToString();     } ... } 
  4. Double-click the Post button control and modify the Click event handler as shown here:

     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>"; } 
  5. Add a new Web form to the project, and name it WebForm2.aspx . Change the pageLayout property of the DOCUMENT element to FlowLayout .

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

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

     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("WebForm1.aspx"); } 
  8. Set the project as the startup project for the solution. Set WebForm1.aspx as the start page in the project and run the project. You will see that you have been redirected to WebForm2.aspx . Enter a name and click the Submit button. You will now see the WebForm1.aspx page with a personalized greeting. If you post a message, you should see that your name is now posted along with the title of the message.

  9. Close this browser window. Then, open another browser window and browse to WebForm1.aspx . You should see that you have again been redirected to WebForm2.aspx to enter your name.

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

 <?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, in which the key is a string type and the value can be any type derived from System.Object . Tables 4.14 and 4.15 discuss the properties and methods of the HttpApplicationState class, respectively.

Table 4.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 in the ASP.NET application.

Table 4.15. Methods of the HttpApplicationState Class

Method

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 an object 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.

The following example demonstrates the use of the Application property to store the applicationwide data:

  1. Add a new Visual C# ASP.NET Web Application project to the solution, and name it Example4_5 . Add a Label control ( lblInfo ) on the form.

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

     private void Page_Load(object sender, System.EventArgs e) {     // Lock the Application before modifying application state     Application.Lock();     if(Application["HitCount"] != null)     {         // Increment the HitCount variable in the application state         Application["HitCount"] = (int) Application["HitCount"] + 1;     }     else     {         Application["HitCount"] = 1;     }     // Unlock the application as the changes are done     Application.UnLock();     //  Fetch the value of HitCount from the application state     lblInfo.Text = "This page has been accessed (" +       Application["HitCount"].ToString() + ") times!"; } 
  3. 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.

  4. Close this browser window. Run the project again; you should see that the page retains the value of the counter and increments it by 1.

Note that the technique used in the previous example 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 the example, you modified the contents of the 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 can 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.

graphics/tip_icon.gif

You don't need to use the Application.Lock() and Application.Unlock() methods in the Application_Start() and Application_End() event handlers because these event handlers are called only once during the lifetime of an application.


graphics/alert_icon.gif

ASP.NET provides an alternative way of maintaining global state for an application using the application data cache. The application data cache should be your preferred choice for storing global data in an ASP.NET application. You'll learn more about this in Chapter 16.




MCAD Developing and Implementing Web Applications with Visual C#. NET and Visual Studio. NET (Exam [... ]am 2)
MCAD Developing and Implementing Web Applications with Visual C#. NET and Visual Studio. NET (Exam [... ]am 2)
ISBN: 789729016
EAN: N/A
Year: 2005
Pages: 191

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net