he sun is shining and I am sitting at a large, umbrella-covered picnic table overlooking a shimmering pond, my state right now is pretty relaxed. I have been fortunate enough to have spent the last few days at a cabin in the northern part of Maine. The birds are chirping, kids are playing, and there’s not a Moose in sight. The only state management I’m concerned with right now is my own state of mind, and right now I am feeling pretty good. State management, whether you are dealing with your own state of mind or if you are working with ASP.NET, is a very fundamental and important task.
In this article I am going to cover the important and sometimes confusing topic of state management. I will explore the state management fundamentals, covering both client-side and server-side state management options.
If you are familiar with Web development then you are well aware that developing Web applications is very different from developing Win32 applications. For those new to Web development I am sure you are finding that there are a number of special challenges associated with developing a Web application. One of the more challenging tasks is persisting state across the application. Before you can persist state across an application, it might help to know what state is.
Quite simply, whether you are building a traditional Windows application or a Web-based application, state is what an application knows about the user, their current interaction with the application, and other pieces of global information. What type of information am I referring to here? Information such as who the user is, where they are in the application, what information they have entered so far, and other application configuration information.
In retrospect, when developing a traditional Windows application, maintaining state wasn’t an issue you had to concern yourself with. You probably never gave it any thought at all. Storing information about the current user, their preferences, or information about the current configuration of the application for that matter, was as simple as storing the information globally in either variables or as properties of an object. Those global variables remain in memory for the application to use until the application is terminated or until they are released. Maintaining state information in a traditional Windows application couldn’t be any easier. Unfortunately, Web applications are a different story entirely.
Web applications are stateless. A user request is received to display a Web page and a Web server obliges by sending the HTML to the user’s browser to display?seems simple enough. It is important to realize that at this point the communication is over until the user requests another page. When the next user request comes in the Web server has no idea who the user is. The Web server doesn’t know what pages it has sent before to that user or if the user has ever been sent any page at all. After the Web server processes each user request it wipes the slate clean and gets ready for the next incoming request, be it from you or someone else.
The question is, if the Web server is continually wiping its memory clean after every request, how can it know who you are and how (or if) it has served you in the past? The answer to that question involves using techniques to store information to help it remember who you are. That is what this article is all about. You can store this, “Hey Web server, remember me?” kind of information, on the client machine (client-based state management options), on the server (server-based state management options), or both.
The client-based techniques include ViewState, query strings, and cookies. The server-based techniques include application state, session state, and database support. I will first describe the client-side techniques and then I’ll cover the server-based techniques.
Client-Based Technique #1: ViewState
I will start with the simplest client-based state management technique to help the server “remember” things about a returning Web page, ViewState. ViewState is built-in into Web Forms pages and automatically retains control values between multiple requests for the same page.
ViewState is implemented through a hidden form field control called __VIEWSTATE. When a Web page is about to be submitted back to the server it takes a look at the state (value) in each control and writes the name of the control and its state into the __VIEWSTATE control. If you look at the source of an .aspx page and examine the __VIEWSTATE control, it will look something like this.
While this mess isn’t easily decipherable to us (yes, it is decipherable), fortunately for us, the ASP.NET parser knows how to extract all of the controls, names, and values from this mess and .NET knows how to use the information from the parser to repopulate the controls.
Flipping ViewState On and Off
You may have guessed that parsing the ViewState information can involve some serious processing on the server for a well-populated page. Since ViewState isn’t a priority for every page you build you can turn it off when you don’t need to use it. Doing so will reduce the demand on server resources and increase the speed of your application.
There are two ways to enable or disable ViewState functionality: at the page level or for individual controls. To disable it at the page level set the enableViewState attribute to False in the Page directive at the top of the page.
<%@ Page enableViewState="False"%>
Similarly, set the EnableViewState property to False to disable ViewState on a specific control (see Figure 1.)
|Figure 1. TextBox Control Property Sheet: You can find the enableSessionState property for a control on the control’s property sheet.|
Hitching a Ride on ViewState
There may be times when you will want to send other information to the server along with the current page so that same information package returns when the page completes its round trip. The ViewState() function accepts the name of the value to store as a parameter and then the value to save is assigned.
For example, suppose I want to track how many times the current page has been submitted by the current user. The Page_Load method code would look like this.
If Not Page.IsPostBack Then ViewState("PageCount") = 1 Else ViewState("PageCount") = _ CInt(ViewState("PageCount")) + 1 End If Me.lblPageCount.Text = _ ViewState("PageCount").ToString
You can create as many ViewState name/value pairs as you like.
Advantages of Using ViewState
Besides just being built in, ViewState provides some other advantages.
- It is easy to implement.
- It retains page and control state for you automatically.
- It does not use server resources since all of the state information is contained within the page itself.
Disadvantages of Using ViewState
Because ViewState information is stored in the page code itself, the potential for ViewState bloat exists for heavily populated pages or pages containing DataGrids.
- Performance problems with ViewState can cause a page to display slowly and cause a delay when it is posted back.
- Page security can be a problem when using ViewState since the ViewState data is available in the page source and, even though it is encrypted, it can still be tampered with.
Client-Based Technique #2: Query Strings
Using query strings is the next client-based technique to help the Web server “remember” things about a returning Web page. If you have ever looked at the URL line when surfing the Web and you’ve seen a very long string of characters, odds are you are looking at query string information. Query strings are a very simple and popular technique to pass data from one Web page to the next.
It works like this: data is appended to the end of a page’s URL and that page pulls the data off the URL line and uses it. Here is an example of a link to a page that passes a user name to a page, such as:
You can separate multiple values using an ampersand (&) like this.
You can code a query string in a number of ways. You can code it directly into an HTML hyperlink like this.
Or you can use the Response.Redirect method like this.
Response.Redirect( _ "www.takenote.com?username=Jim")
You can also construct the query string using Web Form control values like this.
Response.Redirect( _ "www.takenote.com?username=" & _ txtName.Text & "&city=" & txtCity.Text)
One issue you likely encounter using Web Form control values is many browsers do not support blanks in a query string. You can use Server.URLEncode to encode all the characters within the URL, like this.
Response.Redirect("www.takenote.com?username=" & _ Server.URLEncode(txtName.Text) & "&city=" & _ Server.URLEncode(txtCity.Text"")
Using the above line and entering Jim Duffy as the username and Los Angeles as the city would produce a URL like this.
http://www.takenote.com? username=Jim%20Duffy &city=Los%20Angeles
Retrieving Query String Values
Grabbing the query string values off the URL line is quite simple. The following code declares two local variables and stores the UserName and City query string variables.
Dim UserName As String Dim City As String UserName = Request.QueryString("UserName") City = Request.QueryString("City")
Advantages of Using Query Strings
- Query strings are easy to implement.
- Browser support for passing values in a query string is nearly universal.
- Query strings are contained in the HTTP request for a specific URL and do not require server resources.
Disadvantages of Using Query Strings
Query strings aren’t suitable for all types of information, because:
- Query strings are insecure because the information in the query string is directly visible to the user on the address line in the browser
- Many browsers impose a 255 URL character limit which can limit their flexibility.
Client-Based Technique #3: Cookies
Mmmmmm cookies and milk…no, not that kind of cookies. Using cookies is another client-based technique to help the server “remember” things about a returning Web page. Cookies are small pieces of information stored on the client computer. They are limited to storing only character data and they are limited to 4K in size. Session cookies and persistent cookies are the two types of cookies.
Session cookies are stored in-memory during the client browser session. When the browser shuts down the session cookies are lost. You can create session cookies by calling the Add method of the Cookies collection on the Response object. The Cookies collection contains individual cookie objects of type HttpCookie. The following code creates a UserName cookie containing the name Jim.
Dim objCookie As New HttpCookie("UserName", "Jim") Response.Cookies.Add(objCookie)
You read the cookie created above like this.
Persistent cookies work the same way as session cookies. The difference between the two is that persistent cookies have an expiration date. The expiration date indicates to the browser that it should write the cookie to the client’s hard drive. You can create persistent cookies to last for a couple days or a couple years. Keep in mind that because a user can delete cookies from their machine that there is no guarantee that a cookie you “drop” on a user machine will be there the next time they visit your site.
Persistent cookies are typically used to store information that identifies a returning user to a Web site. Typical information found in cookies includes user names and user IDs.
You create persistent cookies the same way as session cookies?by calling the Add method of the Cookies collection on the Response object. Again, the only difference is the persistent cookie has a set expiration date.
Dim objCookie As New HttpCookie("MyCookie", "Rod Paddock") objCookie.Expires = #12/31/2004# Response.Cookies.Add(objCookie)
You read a persistent cookie the same way you read a session cookie.
A cookie dictionary is a single cookie that stores multiple pieces of information. You use the Values property to access and assign new values to the cookie dictionary.
You create a cookie dictionary with code like this.
Dim objCookieDictionary As New _ HttpCookie("Preferences") objCookieDictionary.Values("UserName") = _ "Jim" objCookieDictionary.Values("LastVisit") = _ Now.Date objCookieDictionary.Values("Country") = _ "USA" objCookieDictionary.Expires = _ DateTime.MaxValue Response.Cookies.Add(objCookieDictionary)
You retrieve a value from a cookie dictionary with code like this.
Dim MyCookie As HttpCookie = _ Request.Cookies("Preferences") If Not MyCookie Is Nothing Then Dim Username As String = _ MyCookie.Values("UserName") Dim Country As String = _ MyCookie.Values("Country") Dim LastVisit As String = _ MyCookie.Values("LastVisit") End If
Advantages of Using Cookies
Cookies are great for storing small pieces of frequently changing information on a user’s machine, because:
- Cookies are easy to implement.
- Cookies do not require any server resources since they are stored on the client.
- You can configure cookies to expire when the browser session ends (session cookies) or they can exist for a specified length of time on the client computer (persistent cookies).
Disadvantages of Using Cookies
You should keep in mind though, that:
- A user can delete a cookie.
- A user can refuse a cookie.
- Cookies exist as plain text on the client machine and they may pose a possible security risk since someone (or code) with control of a user’s computer can open and tamper with cookies.
Paying Attention to Cookie Security
You must pay close attention to the type of data you store in cookies. I suggest you follow these guidelines.
- Cookies are not designed to store critical information so storing passwords in a cookie is a bad idea.
- Keep the lifetime of a cookie as short as practically possible.
- Encrypt cookie data to help protect the values stored in the cookie.
Client-Side Method State Management Summary
Table 1 summarizes client-side state management techniques and when you should consider using them.
Table 1: Client-side state management techniques overview.
When to Use
Use when you need to store small amounts of data for a page that posts back to itself.
Use when you are transporting small amounts of non-secure data from one page to another.
Server-Based Technique #1: Application State
Now that you understand the client-based state management techniques let’s explore the server-based state management techniques. We’ll begin with application state.
I’ll start by introducing you to application state variables. They are similar to global variables in traditional Windows applications because they are available from anywhere in the application. What makes them different from Windows application global variables is that they are available to every browser session running the application. You can think of application state variables as a non-existent type of global variable in Windows applications that is available to not only the current user, but to all users running the application. Typically, application state variables contain fairly static data that multiple sessions will share.
You add values to the application state with code like this.
Application("ApplicationName") = "My Application" Application("ApplicationStart") = Now"
You can add objects of any type to application state. You can retrieve application state variables like this.
Dim AppName As String = Application("ApplicationName")
And you use code like this to remove application state variables.
You can remove all the variables from application state by using the RemoveAll method.
Because application state variables are shared across the entire application, there is a possibility that multiple users could attempt to update the same application state variable at the same time. This would not be a good thing. Fortunately Microsoft provided the Lock and Unlock methods to help get around this problem.
The Lock method locks the application state object so that only a single user can update the data. It makes sense to conclude that Unlock releases the Lock, which it does.
Application.Lock Application("PagesDisplayed") += 1 Application.Unlock
You need to understand that an application session starts when the first person accesses the application. In other words, the application does not run if no one visits the site. Once that first visitor shows up and launches the home page for the first time, the application starts.
There are a number of events related to the Application object contained in the global.asax file. Discussing these events is beyond the scope of this article but I suggest you take a look at them and understand what they do and when they are raised.
Server-Based Technique #2: Session State
The second server-based technique involves using session state variables. Since each user is assigned their own unique session when they initially visit a site, think of session state variables as memory variables stored by the Web server local to the current user. They can store information about the user, what tasks they have completed, information in a shopping cart, etc. You can add objects of any type to session state.
You can add values to the session state with code like this.
Session("UserName") = "Jim Duffy" Session("Company") = "TakeNote Technologies"
And you can retrieve session state variables like this.
Dim Company As String = Session("Company")
And you probably guessed that you can remove session state variables with code like this.
You can remove the variables from session state by using the RemoveAll method like this
A session starts when a user accesses a page on a Web site for the first time, at which time they are assigned a unique session ID. The server stores the user’s session ID in the Session.SessionID property. The session ID will be unique for the current session but it is not guaranteed to be unique over time.
A session ends after a pre-defined period of inactivity elapses. Once the server decides that the user has left it removes all session state information for that user. The default session timeout period is 20 minutes. If the user requests another page after 20 minutes has elapsed the server will treat them as a new user. You can change the session timeout value in more than one way. For instance, you can adjust the Session.Timeout property like this.
Session.Timeout = 10
You can also adjust the sessionState timeout setting in the Web.config file.
You can call the Session.Abandon method to end a user session. If a user then tries to access a page the server will assign them a new session ID and it will clear all the previous session variables. You’ll typically use Session.Abandon on sign-out pages.
There are a number of events related to the Session object contained in the global.asax file. Discussing these events is beyond the scope of this article but I suggest you take a look at them and understand what they do and when they are raised.
Session State Modes
By default, all session state information is managed in the same Windows process that the Web server and ASP.NET run in. This is known as running in process. A clear advantage of running in process is performance since all the data is immediately available to the Web server. However, storing the session state in process can have some disadvantages.
- A Web server crash will lose all the current session data.
- You lose session data if the application is restarted for any reason.
- In process session state cannot be shared across multiple Web servers so this limits the scalability of your site. Obviously this is a problem if you plan to scale up to a Web farm.
Fortunately, ASP.NET provides the capability to store session state variables out-of-process. This means that the session state variables are NOT managed within the same Windows process that ASP.NET runs in. The advantage to managing session state out-of-process is that users can seamlessly move from Web server to Web server (though they don’t know it) and still maintain their state. Table 2 lists the session state modes available in ASP.NET.
Table 2: The session state modes available in ASP.NET.
Session state data is stored in the same process as the ASP.NET worker process (default).
Session state is not tracked.
Session state data is stored using an out-of-process server.
Session state data is stored using an out-of-process SQL Server.
Storing Session State Out-of-Process with a StateServer
One technique you can use to store session state variables out-of-process is to use a state server. The .NET Framework includes a Windows service called the ASP.NET State Service that allows you to manage session state out-of-process. You start the ASP.NET State Service by running the following statement at the command prompt.
net start aspnet_state
|Figure 2: The Services dialog box highlighting the ASP.NET State Service.|
You can also start the service by clicking Start, choosing Settings, selecting Control Panel, choosing Administrative Tools, and finally selecting Services to launch the Services dialog box (see Figure 2).
Double-click the ASP.NET State Service entry and specify manual or automatic. With the ASP.NET State Service running you can specify that your site should use it to manage session state by changing the sessionState mode setting in the Web.config file.
Once you’ve made this change you can stop and restart IIS and now the ASP.NET State Service will handle state management duties. IIS looks to the stateConnectionString setting in the Web.config file to determine which server and port to connect to. The example above uses the default local server and port. You can easily change these settings to point at a completely different server.
Storing Session State Out-of-Process with a SQL Server
|Figure 3: TempDB contains the ASPStateTempActions and ASPStateTempSessions after running the InstallSqlState.sql script.|
You can also use Microsoft SQL Server to store session state out-of-process. This works the same way as the StateServer technique except state information is stored in a SQL Server database. The advantage to this approach is that you can cluster multiple database servers and if the one currently managing state fails another can take over the load.
You need to complete a couple of preparatory steps before you can begin storing session state in SQL Server. First you need to run either the InstallSqlState.sql or InstallPersistSqlState.sql script. You’ll find these scripts located in the WindowsMicrosoft.NetFrameworkv1.1.4322 (or later) file folder. The difference between these two scripts has to do with where the ASPStateTempApplications and ASPStateTempSessions tables are created. The InstallSqlState.sql script creates them and other database objects in the TempDB database (see Figure 3) while the InstallPersistSqlState.sql script creates the ASPState database (see Figure 4) and stores the tables there. The advantage of storing session information in the ASPState database instead of in TempDB is that you won’t lose session information if you need to reboot the SQL Server machine.
|Figure 4: ASPState contains the ASPStateTempActions and ASPStateTempSessions after running the InstallSqlState.sql script.|
Next you need to modify Web.config to change the sessionState mode and sqlConnectionString settings.
The advantage to either of the out-of-state process techniques (StateServer or SQL Server) to managing session state is that they are both very scalable. Both techniques will work whether you’re running a single sever or grow into a multi-Web server Web farm.
ASP.NET 2.0 State Management Features
ASP.NET 2.0 will introduce the ability to use a session state data store other than SQL Server. This will be of interest to shops that need to take advantage of the ability to store session state information in a database?Oracle or DB2 for example?but don’t have any experience with SQL Server.
ASP.NET 2.0 will also introduce the ability to replace the default session ID generator with one of your own so that you can generate your own session IDs.
Disabling Session State
|Figure 5: You can enable or disable session state for a page with the enableSessionState property.|
Session state is enabled for all pages in an application by default. You can sometimes improve performance by disabling session state for pages that do not need to use it. To do this you disable page session state by setting enableSessionState to False in the page directive like this.
<%@ Page Language="vb" EnableSessionState="False" %>
You can also set enableSessionState to False in the Property sheet for the page (see Figure 5).
You can choose to disable session state for the entire application by setting sessionState mode = Off in the Web.config file.
Server-Side Method State Management Summary
Table 3 recaps the server-side management techniques available to you and when you should consider them.
Table 3: The server-side state techniques and when to use them.
When to Use
Use when data is fairly static and needs to be available to all users on a site.
Use when storing limited amounts of information specific to an individual user’s session .
Use when you are storing large amounts of data or the data must survive application, session, database, or machine restarts.
Each one of the session state management techniques, both client-side and server-side, depend on using cookies. If the user has configured their browser not to accept cookies then none of the prior techniques for state management will work. Fortunately the ASP.NET framework includes an option to enable cookieless sessions. A cookieless session enables you to track session state without having to rely on browser cookies.
ASP.NET can support cookieless sessions by passing the user’s session ID back to the server in the URL. If you can pass the session ID from page to page you can track the user’s activity and session state without using a cookie.
You can enable cookieless sessions by setting the sessionState cookieless option to True.
Limitations to Cookieless Sessions
A limitation when using cookieless sessions is that you cannot use absolute URLs when linking between pages on your site. You must code every link relative to the current page. For example, these links will work fine:
But the next two links will NOT work with cookieless sessions because clicking on either of them starts a new user session and the existing session values are lost.
The Redirect statement exhibits the same limitation. You must use relative path references when you use cookieless sessions.
It’s a Wrap!
In this article I discussed the important and sometimes confusing essentials of state management. I explored the basics of state management and you learned about the different techniques available on the client-side (ViewState, query strings, and cookies) as well as on the server-side (application state and session state). I also discussed storing session state information in-process and out-of-process. In-process session state management involves storing session variable information in the same Windows process that ASP.NET is running in while out-of-process stores session state in another Windows service or on another machine completely.