View State and State Management


Web applications are built on top of HTTP, which is a stateless protocol. A page and its child controls are created upon each request and disposed of at the end of the request, as we described in Chapter 2, "Page Programming Model." However, it is often necessary to maintain information beyond the duration of a single Web request. The mechanisms that were available in traditional Active Server Pages programming for state management ”such as the Session object on the server and cookies on the client ”are still available in ASP.NET. However, Session state is not scalable, and cookies cannot be depended upon for all applications. ASP.NET offers a new mechanism known as view state that enables a page and its controls to maintain state across a round-trip from the server to the client and back. View state offers a simple and convenient technique to create the illusion of a stateful and continually executing page on top of an inherently stateless environment. In essence, the default view state mechanism involves the persistence of state information through a hidden variable on a page, as we'll see in the next section of the chapter.

The simplest way to use the view state mechanism is through the ViewState property that your control inherits from the Control class. The ViewState property is of type System.Web.UI.StateBag ” a dictionary of key/value pairs in which you can store values of your control's properties. To get a feel for using the ViewState (dictionary) property, let's develop a control that uses ViewState for storing properties.

Using ViewState as the Property Store ” The ViewStateDemoLabel Example

The ViewStateDemoLabel control that we'll develop defines two properties, Text and TextInViewState . We'll store Text in a private field and TextInViewState in the ViewState dictionary. The code for the control is shown in Listing 7-1.

Listing 7-1 ViewStateDemoLabel.cs
 using System; using System.ComponentModel; using System.Web.UI; using System.Web.UI.WebControls; namespace MSPress.ServerControls {     public class ViewStateDemoLabel : WebControl {         private string _text; 
 public string Text {             get {                 return (_text == null) ? String.Empty : _text;             }             set {                 _text = value;             }         }         public string TextInViewState {             get {                 object o = ViewState["TextInViewState"];                 return (o == null)? String.Empty : (string)o;             }             set{                 ViewState["TextInViewState"] = value;             }         }         protected override void RenderContents(HtmlTextWriter writer) {             writer.Write("Text = ");             writer.Write(Text);             writer.Write("<br>");             writer.Write("TextInViewState = ");             writer.Write(TextInViewState);         }     } } 

When the page framework reloads a control after postback, it automatically restores any properties that store their values in ViewState to their state at the end of processing the previous request. You do not have to do any additional work in your control to restore the state of those properties. When a property is stored in the ViewState dictionary, ViewState tracks the property after the control is initialized and saves its value in the control's serializable view state only if the property is modified after initialization. This process minimizes the size of the data that is round-tripped. We'll describe the initialization and tracking phases in more detail in Chapter 9.

Using ViewState as its property storage, a custom control can easily perform basic state management without implementing custom state management logic. If the property is not present in the ViewState dictionary, the property getter must return the default value associated with the property.

The keys used to store properties in ViewState are strings that typically represent the names of properties. We'll list the types of values you can store in ViewState later in this section.

Listing 7-2 shows a page that uses the ViewStateDemoLabel control. The page has two TextBox controls, two Button controls (Submit and Reload), and an instance of the ViewStateDemoLabel control.

Listing 7-2 ViewStateDemoLabelTest.aspx
 <%@ Page Language="C#" %> <%@ Register TagPrefix="msp" Namespace="MSPress.ServerControls"    Assembly="MSPress.ServerControls" %> <html>   <head>     <script runat="server">       void button1_Click(object sender, EventArgs e) {           demolabel1.Text = textbox1.Text;           demolabel1.TextInViewState = textbox2.Text;       }     </script>   </head>   <body>     <form runat="server">       <br>       Enter your first name: <asp:TextBox id="textbox1"          runat="server" />       <br>       Enter your last name:&nbsp <asp:TextBox id="textbox2"          runat="server" />       <br><br>       <asp:Button text="Submit" onClick="button1_Click"          id="button1" Runat="server" />       <asp:Button Text="Reload" Runat="server" id="Button2" />       <br><br>       Here is the output from the ViewStateDemoLabel:       <br>       <msp:ViewStateDemoLabel id="demolabel1" runat="server"          Font-Names="Verdana" Font-Size="Medium" />       <br>     </form>   </body> </html> 

The Submit button has an associated event handler that populates the two properties of the ViewStateDemoLabel instance with user input from the text boxes, thus changing the initial state of the ViewStateDemoLabel instance. The Reload button causes the page to be submitted without changing the state of the ViewStateDemoLabel instance. When the Reload button is clicked, the ViewStateDemoLabel control is loaded with the state that was saved after processing the previous request.

Figure 7-1 shows the page in a browser after a user has entered text in the text boxes and clicked the Submit button.

Figure 7-1. ViewStateDemoLabelTest.aspx viewed in the browser after entering values in the text boxes and clicking the Submit button

graphics/f07hn01.jpg

Figure 7-2 shows the page in a browser after the user reloads it by clicking the Reload button.

Figure 7-2. ViewStateDemoLabelTest.aspx viewed in the browser after clicking the Reload button

graphics/f07hn02.jpg

Notice that in Figure 7-2, only one of the properties of the ViewStateDemoLabel instance is displayed: the TextInViewState property that saves its value in ViewState . Because the Text property of ViewStateDemoLabel uses a private field as its property store, the value of the Text property is not saved across a round-trip. On postback, the page framework re-creates the page and its control tree and restores state using the serialized state. Thus, the TextInViewState property returns the value that was saved in view state after processing the previous request and that was round-tripped, while the Text property returns its default value (an empty string).

To see the hidden variable that contains the serialized state, view the HTML source in your browser corresponding to Figure 7-1 or 7-2. You will see a hidden element on the HTML page named __VIEWSTATE, as shown here:

 <inputtype="hidden" name="__VIEWSTATE"  value="dDwxMTc3NDI5NDg1O3Q8O2w8aTwyPjs+O2w8dDw7bDxpPDExPjs+O2w8dDxw PHA8bDxUZXh0SW5WaWV3U3RhdGU7PjtsPERhdHllOz4+Oz47Oz47Pj47Pj47Pg==" /> 

The hidden __VIEWSTATE field holds the base-64 encoded string that contains the serialized view state for the page and all its controls.

To see the size of the view state for the page and for each control, add the Trace attribute to the Page directive in your .aspx Page ”for example, <%@ Page Language="C#" Trace ="true" %> . The page rendered in your browser will contain a detailed description of the view state size.

More About View State

Let's take a more detailed look at the view state mechanism. In this chapter (and elsewhere in this book), we'll use ViewState to denote the property Control.ViewState and the term view state to denote the overall mechanism in ASP.NET for maintaining state across a round-trip by serializing it into a string representation.

How View State Works

At the end of processing a Web request, the page framework collects the state from all the controls in the control tree and creates a single object graph. The ViewState dictionary of each control is one part of its saved state. We'll examine the other pieces of the saved state in Chapter 10. The page framework serializes the entire object graph into a single string representation, which it then sends to the client as a hidden variable by default. The hidden variable is round-tripped to the server upon postback. (A page developer can change the default persistence mechanism by overriding the LoadPageStateFromPersistenceMedium and SavePageStateToPersistenceMedium methods of the Page class to persist the serialized state elsewhere, instead of round-tripping the state as a hidden field.) When the browser posts the page back to the server, the page framework reads back the hidden variable and deserializes it to repopulate the saved state into the respective controls in the control tree. As part of this reloading, the ViewState dictionary is automatically repopulated with the values that existed in it at the end of the previous request. Any state that a control saved in its ViewState dictionary is thus automatically restored.

Hidden variables have been traditionally used for maintaining state in Web programming. The difference between the traditional use of hidden variables and the view state technique is that the page framework does the work of serializing and deserializing state. In simple controls, all you have to do as a control author is use ViewState for storing your property values. When developing complex controls, you will often have to use a combination of ViewState and custom state management (by implementing IStateManager ), as we'll describe in Chapter 10.

Enabling View State

The Control class exposes a Boolean property named EnableViewState that allows the user of a control to specify whether the view state for that control and its children should be serialized by page framework at the end of a request. The default value of EnableViewState is true . If EnableViewState is false on a control, the view state of the control itself and that of its child controls (if any exist) are not serialized. A page developer can decide which controls to serialize by selectively setting EnableViewState to true or false on the controls in the page.

You should not modify the value of your control's EnableViewState property to disable persistence of view state. This property is meant to provide page developers with a mechanism to optimize their use of view state. If needed, within your control you can modify the EnableViewState property of any child controls that your control might create and contain.

Types You Can Store in View State

The view state of a control can store a variety of types. However, it is optimized in terms of speed and serialization size for a certain set of commonly used types. The types that the view state serialization mechanism natively supports are Int32 , Boolean , String , Unit , and Color . In addition, the view state is optimized for Array , ArrayList and Hashtable objects that contain the types listed earlier. When a type does not fall within this set of optimized types, the value is converted to and from a string by using its associated type converter. Type converters are classes that perform type conversions, including string-to-value and value-to-string conversions. We'll describe type converters in Chapter 10. If a type converter is not found, the page framework serializes the value by using the binary serialization functionality provided by the .NET Framework, which is significantly more expensive. When you use view state in your control, you should try to restrict yourself to the optimized types. Alternatively, you can implement an efficient conversion algorithm in a type converter and associate it with the type.

View State and Performance

It is important to make judicious use of view state because it can create a performance overhead. Any data in the view state that is modified after a control is initialized is serialized by the page framework and sent to the client over the network by default. It is then sent back to the server when the user posts the form. The size of the view state also determines the amount of processing time required for the serialization and deserialization of the view state. You should not save computed values in view state. If there are several properties that depend on common data, you can optimize performance by persisting only one copy of the common data into the view state.

View State and Security

The page framework round-trips the serialized string representation of the view state as clear text with standard base-64 encoding. By default, the page framework also sends a digest of the view state string, which allows the page to check on postback if the view state was tampered with during the round-trip. Thus, a hacker can read but not alter the content of the hidden variable that stores the view state. To make view state more secure, a page developer can choose to encrypt the view state for the page so that it cannot be read during the round-trip.

Note that page security is entirely in the hands of the page developer. As a server control author, you have no control over how a page developer implements security on a page that consumes your control. Therefore, you should not make any assumptions about the security mechanism of the containing page when implementing your control. You should never save any information (such as passwords, connection strings, and file paths) in view state that could compromise the security of an application. You should instead use private member variables to store such information and require the page developer to set those property values on each request.

Using Session and Application Objects

At times, your control might need to reuse data across a user session or even across an application. The following are overall guidelines for using the intrinsic Session and Application objects that ASP.NET provides:

  • Use view state to store data that your control needs to restore its state after postback.

  • Use the System.Web.SessionState.HttpSessionState object, available to your control as Page.Session , to store data that is needed across a user's browser session. You can store sensitive information in Page.Session because this object exists only on the server. The Session object is created for each user session; you do not have to be concerned with thread safety when using the Session object. However, note that a page developer is allowed to turn off the Session state feature for a particular Web application.

  • Use the System.Web.HttpApplicationState object, available to your control as Page.Application , to store data that is needed across an entire application. This object exists only on the server. The Page.Application object is not thread-safe because multiple users could access a page at the same time. You are responsible for thread safety when using the Page.Application object.

At the end of this chapter, we'll look at the PageTracker control, which uses all three mechanisms for maintaining its state.



Developing Microsoft ASP. NET Server Controls and Components
Developing Microsoft ASP.NET Server Controls and Components (Pro-Developer)
ISBN: 0735615829
EAN: 2147483647
Year: 2005
Pages: 183

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