Any dynamic Web application must be capable of managing state information—ASP.NET applications are no different. In this article, I’ll discuss methods for dealing with two types of state information: request state and page state. I’ll also provide some general best practices for dealing with state information.
Getting here late?
In this article, I’ll be building upon concepts I introduced in these two previous articles:
"ASP.NET offers new state management techniques"
"Use ASP.NET caching to optimize your Web applications"
Working with request state
Requests to an ASP.NET Web application are processed by the ASP.NET runtime engine in a pipeline process. As the request is processed, it is passed from the Web server (IIS) to the HTTP application, where events in global.asax are fired on to HTTP modules. In the modules, session state, security, and other information is processed. Finally, specific HTTP handlers render the page. Figure A illustrates this process.
|Generalized ASP.NET request processing|
During processing, information is attached to an HttpContext object that is finally accessible in any Page and UserControl classes through the Context property.
In addition to allowing access to other information about the current request, the HttpContext object can also be populated with custom data that is accessible to the remainder of the request. For example, the BeginRequest event in the global.asax code-behind class could contain code to read a database that contained dynamic page layout information. This information could then be placed in the HttpContext object and accessed from any page to load user controls and change page display options programmatically.
Another example would be retrieving user input from a Web page and then passing the information to another page by placing it in context, like so:
In this scenario, notice that the items in the cache are name-value pairs that can be populated with any type of data. For the data to be retrieved on another page, however, the Transfer method of the Server object must be used to execute the next page instead of Response.Redirect with a query string, because the latter instructs the browser to create a new request for the page, thereby creating a new HttpContext. Server.Transfer, on the other hand, continues execution on the server in the same request and preserves the existing HttpContext.
Working with page state
One of the most important differences in the architecture of ASP.NET from that of ASP is the inclusion of a programming model that allows for event-based development analogous to the forms model of Visual Basic 6. This architecture creates the appearance of a static form-based development environment by saving the ViewState of any ASP.NET server controls on a page.
Each ASP.NET page contains a FORM tag with a runat attribute. When this attribute is encountered and is set to the string literal server, a FORM tag is written to the HTML stream that posts the form back to itself. In addition, a hidden INPUT tag named __VIEWSTATE is added to the form; it contains a base-64 encoded string representing the state of the properties for the controls on the form.
The nice thing about ASP.NET’s automatic ViewState management is that it keeps you from having to manually save the state of your controls, and it does so in a browser-independent and efficient manner. The state information is applied to the page’s controls when the page is processed, allowing controls to be programmatically manipulated without worrying about repopulating them.
Disabling automatic ViewState management
The ViewState of individual controls and the form as a whole can be controlled by setting the EnableViewState property in code or as an attribute in the Page directive. By default it is set to True, but setting it to False can improve performance by decreasing the amount of data sent to and from the server.
One problem arises when an ASP.NET page is loaded or posted back to the server: The page is reconstructed and re-executed from scratch. In other words, if the code-behind class contains class-level variables or custom properties, these are not automatically saved in the ViewState. However, you can programmatically manipulate the underlying System.Web.UI.StateBag object and add custom information to it using the ViewState property of the Page and UserControl classes.
For example, consider tracking the information used to sort a DataGrid. You could add the information needed for the page to remember which column was previously sorted and in what order by adding properties to the ViewState. Listing A shows one way this could be accomplished in VB.NET.
Note that the code first checks to determine whether a SortField key exists in the ViewState property of the Page class. If not, the keys are created and populated with the column that is to be sorted and the default sort order, ascending in this case. The new sort column is then compared with the information in the StateBag, and, if equal, the sort order is toggled. Finally, the new column and sort order are placed back in the StateBag.
Using the StateBag in this way has several advantages over storing such information in the Session state. In particular, there is less overhead involved because the values are not persisted anywhere and simply travel with the form. In addition, the StateBag promotes information hiding because only this particular Web Form needs to see these values. In classic ASP, developers would have had to create their own StateBag-like implementation using hidden form fields.
ASP.NET provides a robust set of options for dealing with state information in Web applications, and I’ve covered a lot of ground in this series. To summarize when and how to best use the options available, consider the chart in Figure B.