State Mechanisms in ASP
Originally Published 3/2/2001 on WebReview.com
Currently, there are four major methodologies that are used to store data for web
applications in Microsoft’s Active Server Pages. These methods have been discussed
individually in the past, but there seems to be a need for an overview of those
methods that includes explanations of when it may be appropriate to use them. In
this article, I will give a brief introduction to maintaining state in ASP and will
present each of the four, examining the benefits and costs of each in the hopes
of assisting you in determining what methodology best suits your application.
As you know, HTTP, the protocol on which the Web transports its data, is stateless.
That means that if you want a web application to remember some information from
one request (page load) to the next, the web developer has to implement some type
of state mechanism to store the data. There are four methods that are typically
used to store this data. The information can be stored on the client machine in
hidden fields or in cookies, on the server using the ASP session object, or on the
server using a custom method such as in a database. No matter which method you choose,
at least one data item will have to be stored on the client, probably in the form
of a cookie, in order to identify that user. We’ll look at each of these methods
in some detail.
Client Side State Mechanisms
The most straightforward way of maintaining state using ASP (or pure HTML for that
matter) is to store the values of the variables you wish to save in hidden form
fields. This data can be sent to the server using either the HTTP Get or Post method.
If the Get method is used, all the data will appear on the URL line in the Address
bar at the top of the browser. If the Post method is used, the data will be hidden
from view unless the user selects the “view source” option of their browser. Either
way, the data is very easy to modify at the client side. This method is implemented
in ASP by using an HTML input field to send the data to the browser, and the ASP
Request object to read the values back into the server. For example:
<input type=”hidden” name=”UserName” value=”Joe User”>
stores the value “Joe User” in the HTML field named “UserName”. Then, the ASP statement:
<% sUserName = Request.QueryString(“UserName”) %>
will read this value back into your ASP application. While this method of storing
state information is fairly easy to understand, it has some severe limitations.
First of all, it requires that every page that the user hits contain a form that
maintains this state information. If the user were to type in a URL into the address
field on his or her own, click on a link that is not part of the form that holds
the data, close his or her browser, or click on a favorite, then all of the information
will be lost. Because of these limitations, and others discussed below in reference
to using cookies, I do not recommend using this methodology. Instead, if you wish
to store data on the client-side, take a look at the next method of maintaining
state, the HTTP Cookie.
HTML Cookies are a somewhat more reliable method of maintaining state. A cookie
is a named piece of data stored on the client machine by the browser, and sent to
the server in the header of any page request to the same server that originally
sent the cookie to the client. While this all may sound complicated, Active Server
Pages makes using cookies to store data on the client-side easy by providing properties
of the request and response objects that handle reading and writing cookies. For
example, the ASP statement:
<% Response.Cookies(“Username”).Value = “Joe User” %>
Sets the value of the cookie Username to “Joe User” and stores that information
in the client’s browser. Then, at the next request, we can execute the following
statement:
<% sUserName = Request.Cookies(“Username”).value %>
This retrieves the value stored in the Username cookie from the browser. Using cookies
is virtually as straightforward a way of storing state as the HTML form since each
item is simply stored in the users browser under the domain name from the Address
box of the browser. All cookies from that domain will be sent with the request and
can be read by the server-side ASP code each time the domain that supplied the cookie
is accessed by that particular browser. However, this information is far safer since
the user can go to another site or close his or her browser and the information
will still be available. This methodology is often preferred to server-side methods
when only a few bytes of information need to be maintained since it does not require
creating any type of data store on the server-side. Also, may purists believe that
client data belongs to the client and therefore should be stored on the client computer.
Disadvantages to using cookies, like the HTML form method, include the fact that
all of the data stored will have to be sent over the wire each time a page is loaded
from the issuing domain. This can significantly impact loading speed especially
if large amounts of data are being sent across a small pipe. In addition, data stored
in cookies is not secure. This data can be modified or even deleted at the client
side, and unless the connection with the client is encrypted, is sent over the Internet
in plain text. Applications that require large amounts of data to be stored, or
that need to maintain the state of data that should not be able to be modified by
the client are not good candidates for using client-side mechanisms by themselves.
One variation of this method that can reduce some of these downfalls involves storing
all information in one encoded cookie on the client. This implementation can reduce
bandwidth usage somewhat if a good compression algorithm is used and can also increase
security slightly over the standard cookie implementation. This variation is the
implementation Microsoft has chosen as a standard for their .NET initiative.
Server-Side State Mechanisms
The first of the server-side methodologies involves the use of the Microsoft Server-Side
state objects native to ASP. These are the Application object used for maintaining
application level state in an ASP app (all users of the app share this data) and
the Session object used for maintaining session level (per-user) data. As with the
cookie method, ASP handles the details of implementation for you, allowing the developer
to store and retrieve data easily with statements such as:
<% Session(“Username”).value = “Joe User” %>
And
<% sUsername =Session(“Username”).value %>
Application level data can be stored and retrieved just as easily by replacing the
Session object with the Application object as in the following example:
<% Application(‘UserCount”).value = Application(“Usercount”).value + 1 %>
And
<% lUserCount = Application(“UserCount”).value %>
The biggest advantage to using this method comes when storing medium quantities
of scalar data. Since information stored in these objects is kept in the memory
of the server, storage and retrieval can be quite fast and can scale reasonably
well to handle higher volumes of traffic. Also, since the vast majority of the data
is stored on the server, bandwidth requirements can be significantly lower than
the client-side methods discussed earlier. However, there can be major drawbacks
to using this method for high-traffic websites. First off, when information is stored
in the memory of the web-server, that data is not available to other servers, rendering
the use of server-farms impossible with this technology today. If it is likely that
your application will be moved to a server-farm in the future, you may wish to avoid
using this memory-resident methodology (Microsoft has promised a solution to this
particular problem in the next release of ASP called ASP+). Also, since this data
is never persisted to the file system, after the session times-out (for session
level data) or the Application ends (for Application level data), the information
is lost. If a customer comes back after a month, it is very likely that everything
they did in their previous visit will no-longer be available to the application.
In addition, a server crash would cause the loss of Session/Application data.
Another failing of this system is in its ability to store non-free-threaded objects
such as those created with Visual Basic 6. Microsoft’s Internet Information Server
(IIS) allocates twenty threads by default to a pool that can be used for objects
stored in Session and Application state. If these objects are not free-threaded,
they can only be activated on the thread that they were created on. Applications
that get more than 20 concurrent users or store a number of objects in this thread-pool
run the risk of bottlenecks when accessing objects that are limited in what thread
they can run on. Simply put, storing objects that are Single or Apartment threaded
in the Session or Application objects can cause significant performance problems
for sites that receive more than twenty concurrent users. Another potential limiting
factor of this methodology is that since all of the data is stored in the memory
of the server, large quantities of data for a large number of users can end up utilizing
a majority of the server’s available memory. I highly recommend running performance
tests using Microsoft’s Web Application Stress Tool (a free download) to see what
kind of impact on memory and CPU usage this methodology has on your particular server
and application. Please note that this built-in method of storing data server-side
still requires that a key to the server data be stored on the client. In this case
the ASPSession cookie is used automatically by ASP to identify the user and store/retrieve
that user’s data.
For those applications that get a large number of concurrent users and need to store
object data or whose data storage requirements exceed the memory constraints of
the web server, a custom solution is required. These implementations of state mechanisms
may store the information in a database, or in the file system of the server such
as in an XML file. Clearly such a solution is more costly than the other two methods,
both in development and maintenance costs and may require a higher-end server or
even an additional database server to implement. However, these custom solutions
can implement the ability to store non-scalar data such as VB objects without running
into thread-pooling issues, and can be implemented such that a server-farm is still
useable by the application. This methodology is also best when the data needs to
be stored for long periods of time (typically anything over 20-minutes, the default
length of an ASP session). For example, data stored in a database can be kept there
permanently, or deleted at the application’s discretion perhaps by a cleanup program
that deletes all data that has not been accessed within the last year. Most solutions
of this type will involve the creation of custom objects that replace the Application
and/or Session objects of ASP, however, the state could be maintained simply by
making database or file-system calls from within ASP at some cost of performance.
As with the Application/Session method, some form of client-side data will probably
be required to act as an index to the data stored on the server. In this case, the
developer will be responsible for setting up and maintaining this information on
the client.
In summary, the key to knowing which type of state method is best for your application,
is to know your app. Sites requiring small amounts of data that do not need to be
secured and where the data may be traveling over a large pipe can use a client-side
implementation, most likely the pure-cookie methodology. Applications that need
to store their data on the server-side to avoid security risks, but do not require
non-scalar data, large quantities of data, or long-term storage of that data are
good candidates for the built-in ASP state mechanism consisting of the Application
and Session objects. Finally, high-volume sites requiring large quantities of secure
or non-scalar data that needs to be stored over a long period should use a custom
solution. Whatever implementation you choose, be certain to performance-test your
application to be sure that it meets your needs both now and in the future.