State Management in ASP.NET

3. March 2003 15:31 by Chris in dev  //  Tags:   //   Comments (0)

Note that this article was first published on 02/01/2003. The original article is available on DotNetJohn.

Introduction

The web is a stateless medium – state is not maintained between client requests by default. Technologies must be utilized to provide some form of state management if this is what is required of your application, which will be the case for all but the simplest of web applications. ASP.NET provides several mechanisms to manage state in a more powerful and easier to utilize way than classic ASP. It is these mechanisms that are the subject matter for this article.

Page Level State - ViewState

Page level state is information maintained when an element on the web form page causes a subsequent request to the server for the same page – referred to as ‘postback’. This is appropriately called ViewState as the data involved is usually, though not necessarily, shown to the user directly within the page output.

The Control.ViewState property provides a dictionary object for retaining values between such multiple requests for the same page. This is the method that the page uses to preserve page and control property values between round trips.

When the page is processed, the current state of the page and controls is hashed into a string and saved in the page as a hidden field. When the page is posted back to the server, the page parses the view state string at page initialization and restores property information in the page.

ViewState is enabled by default so if you view a web form page in your browser you will see a line similar to the following near the form definition in your rendered HTML:

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

When a page is re-loaded two methods pertaining to ViewState are called: LoadViewState and SaveViewState. Page level state is maintained automatically by ASP.NET but you can disable it, as necessary, by setting the EnableViewState property to false for either the controls whose state doesn’t need to be maintained or for the page as a whole. For the control:

 <asp:TextBox id=”tbNamerunat=”serverEnableViewState=”false/> 

for the page:

 <%@ Page EnableViewState=”false” %> 

You can validate that these work as claimed by analyzing the information presented if you turn on tracing for a page containing the above elements. You will see that on postback, and assuming ViewState is enabled, that the LoadViewState method is executed after the Page class’ Init method has been completed. SaveViewState is called after PreRender and prior to actual page rendering.

You can also explicitly save information in the ViewState using the State Bag dictionary collection, accessed as follows:

 ViewState(key) = value 

Which can then be accessed as follows:

 Value = ViewState(key) 

It is important to remember that page level state is only maintained between consecutive accesses to the same page. When you visit another page the information will not be accessible via the methods above. For this we need to look at other methods and objects for storing state information.

Session Level State

What is a user session? Slightly simplifying it’s the interaction between a user’s first request for a page from a site until the user leaves the site again. Now what if you login into this site at your first request, assuming this is a site you have previously registered with. How does the application remember who you are for the rest of the ‘session’? Or if you have items in your shopping cart within an e-commerce web application how does the application ‘remember’ this information when you request to go to the checkout?

The answer may well be session state though the underlying mechanism by which this is achieved may be one of several options. ASP.NET creates a session (it reserves a section of memory) for a user when they first arrive at the site and assigns that user session a unique id that is tied to that section of memory. By default, ASP.NET then creates a cookie on the client that contains this same id. As this id will be sent with any subsequent http requests to this server ASP.NET will be able to match the user against the reserved section of memory. Further the application can store data related to that user session in this reserved memory space to maintain state between requests. It must be remembered that using session state is using server resources for every user of the site so you need to consider the resources required of items you choose to store.

An example:

 session(“name”)=”Chris Sully” 

sets a session variable with key ‘name’ and value “Chris Sully”. To retrieve/ display this we use:

 lblUserName.text=session(“name”) 

In this case assigning to the text property of a label web server control.

By default the resources associated with this session state maintenance are released if the user does not interact with the site for 20 minutes. If the user returns after a 20 minutes break a new session will have been created and any data associated with their previous session will have been lost. However, you can also destroy the session information for a user earlier within the application if so desired via

 Session.Abandon 

and you may also change the default value from 20 minutes. To redefine the session timeout property you use:

 Session.Timeout = 5 

Alternatively, and representing a more likely scenario, you would specify the value in your web.config file:

 <configuration>
   <system.web>
     <sessionState timeout=10 />
   </system.web>
 </configuration> 

which would half the default timeout from 20 to 10 minutes.

We'll return to some of the other sessionState properties in subsequent sections.

Looking at a little more detail at the session initialization process:

  1. User makes a request of the server
  2. ASP.NET retrieves the user’s sessionID via the cookie value passed in the HTTP request from the client computer. If one does not exist ASP.NET creates one, and raises the Session_OnStart event (which can be reacted to in the global.asax, amongst other locations).
  3. ASP.NET retrieves any data relating to the sessionID from a session data store. This data store may be of a variety of types, as we shall explore in subsequent sections.
  4. A System.Web.SessionState.SessionState object is created and populated with the data from the previous step. This is the object you access when using the shortcut session(“name”)=”Chris Sully”

There is also a Session_OnEnd which you can code against in your global.asax.

SQLServer

We can use SQLServer to store our session state. We can use other databases if we want to but ASP.NET includes built in support for SQLServer as well as other data stores that make life easier for developers. As you might expect, SQLServer should be the choice for storage of session information in high end, performance critical web applications.

To enable session state storage with SQLServer we'll need the infrastructure to support this, i.e. the tables and stored procedures. Microsoft has supplied these and they are located at

C:\winnt\Microsoft.net/framework/[version directory]

On my system:

C:\winnt\Microsoft.net/framework/v1.0.3705/InstallSQLState.sql

And you also have the TSQL to remove the setup: UninstallSQLState.sql.

So, to enable SQLServer session support open up and execute InstallSQLState.sql in query analyzer. If you then investigate what’s new in your SQLServer setup you will see a new database named AspState with 15 or so stored procedures used to insert and retrieve the associated session data. You won’t see any new tables! However, if you expand the tempdb database and view the tables therein, you will see two new tables: ASPStateTempApplications and ASPStateTempSessions which is where our session state information shall be held.

Now, all we need to do, as ASP.NET takes care of everything else for us, is modify web.config so that the ASP.Net application knows it should be using SQLServer for session state management:

 <configuration>
   <system.web>
     <sessionState mode=”sqlserversqlConnectionString=”connectionString/>
   </system.web>
 </configuration> 

where you should replace connectionString with that for you own machine.

If you want to test this, create a simple page which adds an item to the session state. This can be as simple as assigning a value to a session variable a la: session(“name”)=”Chris Sully”, perhaps simply placing this in the OnLoad sub of an otherwise blank aspx. View this in your browser. Don’t close the browser window after the page is loaded as you’ll end the session. Remember that after the first request by default the session will last 20 minutes.

If you now examine the contents of the ASPStateTempApplications table in tempdb either with Enterprise Manager or Query Analyser, you will see an entry corresponding to the above set session variable.

The other possibly important consideration is that the session data is stored external to the ASP.Net process. Hence, even if we restart the web server the information will remain available to subsequent user requests. We’ll look at another mechanism for such data isolation shortly.

Cookies

We’ve already introduced that cookies are central to the concept of session – they are the client half of how session state is maintained over browser requests. As well as using them for user identification purposes we can also use them to store custom session information. Cookie functionality is exposed via the HttpCookie class in .NET. This functionality may also be accessed via the Response and Request ASP.NET classes.

Cookies used in this way don’t tie in strongly with the inbuilt state management capabilities of .NET but they can provide useful custom session state management functionality.

To add a cookie (store on the client browser machine) you use the response object, e.g.:

 response.cookies(“ExampleCookie”)(“Time”)= datetime.now.tostring(“F”) 

i.e.,

 response.cookies(“CookieName”)(“keyName”) = value 

‘F’ refers to the Full date/time pattern (long time) by the way.

To retrieve a cookie you use the request object. The cookie is associated with the server URL and hence will be automatically appended to the request parameter collection and hence accessible as follows:

 TimeCookieSet = Request.Cookies(“ExampleCookie”)(“Time”) 

There are other options available. For example, you may set the Expires property of the cookie. This may be a fixed date or a length of time from the present date:

 Response.cookies(“ExampleCookie”).Expires = DateTime.FromString(“12/12/2003”)
 
 Response.cookies(“ExampleCookie”).Expires = DateTime.Now.AddMonths(6) 

Cookie Munging

You may wish to configure your applications to use session state without relying on cookies. There could be several reasons for this:

  1. You need to support old browser types that do not support cookies.
  2. You wish to cater for people who have chosen to disable cookie support within their browser.
  3. Certain types of domain name redirection mean that cookies / conventional state management will not work.

Cookie munging causes information regarding the session state id to be added to URL information. Thus the link between client and session data on the server is maintained.

It is simply enabled, as follows:

 <configuration>
   <system.web>
     <sessionState cookieless=”true/>
   </system.web>
 </configuration> 

If you change your web.config file to the above and then view a page which uses both the session object and postback you’ll see ASP.Net has inserted some extra information in the URL of the page. This extra information represents the session ID.

Cookie munging certainly does the job in instances where it is required but should be avoided where it is not, as it is insecure being susceptible to manual manipulation of the URL string.

Session State Server

Session State Server runs independently of ASP.Net, the current application, web server and (possibly) the server meaning you have good isolation of data and hence if there is a problem with the web server you may still be able to recover the user session data. This without the need for SQLServer. The State Server also presents a number of extra facilities including the choice of where and how to deploy the facility.

You can run the StateServer in the same process as the ASP.Net application (“InProc” – the default). This is similar to how classic ASP managed session state. Why would we want to do this when we have just lauded the benefits of data isolation? Performance is the answer – data stored in the same process is accessed quickly.

You can test this via restarting IIS (iisreset) when you know you have some session data in your application. You could also try restarting the ASP.NET application via the MMC snap-in, the effect is the same. This is achieved by removing and recreating the IIS application (right click-properties on the application sub-directory/ virtual directory).

A couple of simple test scripts would be:

1:

 <configuration>
   <system.web>
     <sessionState cookieless=”true/>
   </system.web>
 </configuration><%@ Page Language="VB" %>
 <html>
 <head>
 </head>
 <body>
   <form runat="server" ID="Form1">
   <% session("test")="test" %>
   </form>
 </body>
 </html>  

2:

 <%@ Page Language="VB" %>
 <html>
 <head>
 </head>
 <body>
   <form runat="server" ID="Form2">
   <%=session("test")%>
   </form>
 </body>
 </html> 

So, if you run 1, then 2 directly after without closing the browser window, the value will be maintained and you’ll see ‘test’ displayed. If you reset IIS or the IIS application in between the browser requests session information will be lost.

You can also run State Server out of process (“Out-of-Proc”) which means that session state information can be stored in alternative locations to the ASP.NET process space. Hence, if there is a problem with the application or web server state is maintained. In this scenario, the ASPNETState process (aspnet_state.exe) is used, which runs as a service, storing session data in memory.

First thing we need to do therefore is make sure this service is up and running. This can be done via the command line:

Net start aspnet_state

Though if you’re going to this out of process support for an application you will want to setup the service to start on machine boot up (admin tools – services).

Next it’s back to that Web.Config file to tell the application to use the facility:

 <configuration>
   <system.web>
     <sessionState mode=”stateserverstateConnectionString=”tcpip=127.0.0.1:80/>
   </system.web>
 </configuration> 

In actual fact the stateConnectionString attribute is not required when pointing to a port on the local machine, as it is above (which supplies the default setting), but is important if you wish to use another machine and port for extra security/ reliability. It is included to demonstrate the syntax.

If you now go back and try the session maintenance test you won’t lose that session data.

Application level state

Using Application state is similar to using session state: the HttpApplicationState class contains an Application property that provides dictionary access to variables:

 Application(“key”) = value 

The difference with session state is that data is stored per IIS application as opposed to per user session. Thus if you set up:

 application(“name”)=”Chris Sully” 

in your global.asax file for the application this value is available to all pages of your application and will be the same value for all users who visit.

Setting state information is not limited to global.asax – any page of the application being run by any user can do this. There is an implication here – multiple users trying to change the value of an application variable could lead to data inconsistencies. To prevent this the HttpApplicationState class provides the lock method that ensures only one user (actually a process thread) is accessing the application state object at any one time. Thus you should lock before amending an application value and unlock immediately afterwards so others have access to the variable.

Other options for state management: caching

Another method of storing data on the server is via the cache class. This effectively extends the capabilities of storing data at the application level. Frequently used data items may be stored in the cache memory for presentation. For example, data for a drop down list may be stored in a cached object so that the cached copy is used rather than obtaining the data from the database on every occasion.

You may store your objects in cache memory and set the properties of the cache to control when the cache might release its resources. For example, you might use the TimeSpan property that specifies how long the item should remain in the cache after it is last accessed. You can also specify a dependency of the cached item on a datasource, for example an XML file. If this file is changed the chance can be programmed to react to this event accordingly and update the cached object.

For further information on this subject see my article on caching on dotnetjohn.

Conclusion

I hope this article has provided a useful overview of the state management options and support in .NET. With all the forms of state management there exists a balance between the needs of the application and the associated resources used.

In particular, be aware that page level state is enabled by default and should be disabled if not required, particularly if you are manipulating significant amounts of data within DataBound controls. As well as using server resources, leaving ViewState enabled in such a situation will increased the page size, and hence download times, significantly. In such a situation it may be better to cache the data on the server for the postback rather than transmit the data in the ViewState, or even rely on the data caching facilities of your chosen DBMS.

ASP.Net provides significantly extended support for session state maintenance via SQLServer and Session State Server. The choice is down to the needs of your application and, in particular, how important data isolation from your IIS application is.

References

.NET Framework SDK documentation

ASP.NET: Tips, Tutorials and Code Sams Mitchell et al.

About the author

I am Dr Christopher Sully (MCPD, MCSD) and I am a Cardiff, UK based IT Consultant/ Developer and have been involved in the industry since 1996 though I started programming considerably earlier than that. During the intervening period I've worked mainly on web application projects utilising Microsoft products and technologies: principally ASP.NET and SQL Server and working on all phases of the project lifecycle. If you might like to utilise some of the aforementioned experience I would strongly recommend that you contact me. I am also trying to improve my Welsh so am likely to blog about this as well as IT matters.

Month List