Managing Sessions

One of the challenges to developing a successful Web application is maintaining user information over the course of a visit, or session, as the user travels from page to page in an application. HTTP is a stateless protocol, meaning that your Web server treats each HTTP request for a page as an independent request; the server retains no knowledge of previous requests, even if they occurred only seconds prior to a current request. This inability to remember previous requests means that it is this difficult to write applications, such as an online catalog, where the application may need to track the catalog items a user has selected while jumping between the various pages of the catalog.

ASP provides a unique solution for the problem of managing session information. Using the ASP Session Object object and a special user ID generated by your server, you can create clever applications that identify each visiting user and collect information that your application can then use to track user preferences or selections.

ASP assigns the user ID by means of an HTTP cookie, which is a small file stored on the client's computer. So, if you are creating an application for browsers that do not support cookies, or if your customers might set their browsers to refuse cookies, you should not use ASP's session management features.

caution Caution ASP shares a pool of session identification cookies between all applications within the same process. A malicious user can manipulate an established session cookie from an application to which they have valid access and use it to gain access to another application within the same process. This can only happen if the session identification cookie is unencrypted. To ensure that never happens, always use Secure Sockets Layer (SSL) with application that use session cookies. For information on configuring SSL for your application, see "Secure Sockets Layer" in IIS Help, which is accessible from IIS Manager.

Starting and Ending Sessions

A session can begin in four ways:

  • A new user requests a URL that identifies an .asp file in an application, and the Global.asa file for that application includes a Session_OnStart Event procedure.
  • A user stores a value in the Session object.
  • A new session automatically starts whenever the server receives a request that does not contain a valid SessionID cookie.
  • A user requests an .asp file in an application, and the application's Global.asa file uses the <OBJECT> tag to instantiate an object with session scope. See Using Components and Objects for more information about using the <OBJECT> tag to instantiate an object.

A session automatically ends if a user has not requested or refreshed a page in an application for a specified period of time. This value is 20 minutes by default. You can change the default for an application by setting the Session.Timeout property on the Application Options property sheet in the Internet Information Services snap-in. Set this value according to the requirements of your Web application and the memory capacity of your server. For example, if you expect that users browsing your Web application will linger on each page for only a few minutes, then you may want to significantly reduce the session timeout value from the default. A long session timeout period can result in too many open sessions, which can strain your server's memory resources.

If, for a specific session, you want to set a timeout interval that is shorter than the default application timeout, you can also set the Timeout property of the Session object. For example, the following script sets a timeout interval of 5minutes.

  <%  Session.Timeout = 5  %>

You can also set the timeout interval to be greater than the default value, the value determined by the Session Timeout property.

note Note Timeout only applies to sessions that have state. During a stateless session the Session object does not contain content or static objects. This type of session automatically ends after the request is processed and is recreated on the next request from the same browser.

Alternatively, to deliberately end a session you can use the Session.Abandon method of the Session object. For example, you can provide a Quit button on a form with the ACTION parameter set to the URL of an .asp file that contains the following command.

  <% Session.Abandon %>

note Note A user's requests that are queued up for execution prior to initiating Session.Abandon will execute within the context of the session being abandoned. After Session.Abandon has completed execution, new incoming requests will not be associated with the session.

About SessionID and Cookies

The first time a user requests an .asp file within a given application, ASP generates a SessionID. A number produced by a complex algorithm, the SessionID uniquely identifies each user's session. At the beginning of a new session, the server stores the Session ID in the user's Web browser as a cookie.

The SessionID cookie is similar to a locker key in that, as the user interacts with an application during a session, ASP can store information for the user in a "locker" on the server. The user's SessionID cookie, transmitted in the HTTP request header, enables access to this information in the way that a locker key enables access to a locker's contents. Each time that ASP receives a request for a page, it checks the HTTP request header for a SessionID cookie.

After storing the SessionID cookie in the user's browser, ASP reuses the same cookie to track the session, even if the user requests another .asp file, or requests an .asp file running in other application. Likewise, if the user deliberately abandons or lets the session timeout, and then proceeds to request another .asp file, ASP begins a new session using the same cookie. The only time a user receives a new SessionID cookie is when the server administrator restarts the server, thus clearing the SessionID settings stored in memory, or the user restarts the Web browser.

By reusing the SessionID cookie, ASP minimizes the number of cookies sent to the browser. Additionally, if you determine that your ASP application does not require session management, you can prevent ASP from tracking session and sending SessionID cookies to users.

ASP will not send the session cookies under the following conditions:

  • If an application has session state disabled.
  • If an ASP page is defined as sessionless, that is, a page containing the <%@ EnableSessionState=False %> tag. For more information, see Sessionless ASP Pages.

You should also note that SessionID cookies are not intended to provide a permanent or secure means for tracking users across multiple visits to a Web site. The SessionID information stored in the server computer's memory can be easily lost or impersonated by a malicious user. If you want track users who visit your Web application over a longer periods, you must create a user identification by storing a special cookie in a user's Web browser and saving the cookie information to a database. If you do so, configure your application to use SSL in order to encrypt the SessionID and protect it from malicious users. For more information, see Using Cookies and see "Secure Sockets Layer" in IIS Help, which is accessible from IIS Manager..

Storing and Removing Data from the Session object

The Session object provides a dynamic, associative array into which you can store information. You can store scalar variables and object variables into the Session object.

To store a variable in the Session object, assign a value to a named entry in the Session object. For example, the following command stores two new variables in the Session object:

  <% 
  Session("FirstName") = "Jeff"
  Session("LastName") = "Smith" 
%>

To retrieve information from the Session object, access the named entry. For example, to display the current value of Session("FirstName"):

  Welcome <%= Session("FirstName") %>

You can store user preferences in the Session object, and then access that preference to determine what page to return to the user. For example, you can allow a user to specify a text-only version of your content in the first page of the application and apply this choice on all subsequent pages that the user visits in this application.

  <% If Session("ScreenResolution") = "Low" Then %> 
  This is the text version of the page.
<% Else %> 
  This is the multimedia version of the page.
<% End If %>

You can also store an object instance in the Session object, although doing so can affect server performance. For more information, see Setting Object Scope.

At times, it may be desirable to delete items stored in the Session object. For example, it is not uncommon for users visiting an online retail store to change their minds, abandon a list of purchase items, and decide on a completely different set of selections. In such a case it may be expedient to update the Session object by deleting inappropriate values.

The Session object's Session.Contents Collection collection contains all of the variables that have been stored (that is, those stored without using the HTML <OBJECT> tag) for a session. By using the Contents collection's Session.Contents.Remove method, you can selectively remove a reference to a variable that was added for the session state. The following script illustrates how to use the Remove method to purge an item, in this case user discount information, from the Session object:

  <%
  If Session.Contents("Purchamnt") <= 75 then 
    Session.Contents.Remove("Discount")
  End If 
%>

If desirable, you can also use the Contents collection's Session.Contents.RemoveAll method to completely remove all variables stored for the session:

  Session.Content.RemoveAll()

Using the Remove method you can choose to delete items by name or by index. The following script demonstrates how to cycle through values stored in the Session object and conditionally remove values by index:

  <%
  For Each intQuote in Session.Contents
    If Session.Contents(intQuote) < 200 Then
      Session.Contents.Remove(intQuote)  
    End If
  Next
%>

Managing Sessions Across Multiple Servers

ASP session information is stored on the Web server. A browser must request pages from the same Web server for scripts to access session information. On cluster of Web servers (where many Web servers share the responsibility for responding to user requests) user requests will not always be routed to the same server. Instead, special software distributes all requests for the site URL to whichever server is free, a process called load balancing. Load balancing makes it difficult to maintain session information on a cluster of Web servers.

To use ASP session management on a load-balanced site, you must ensure that all requests within a user session are directed to the same Web server. One way to do this is to write a Session_OnStart Event procedure that uses the Response object to redirect the browser to the specific Web server on which the user's session is running. If all links in your application pages are relative, future requests for a page will be routed to the same server.

For example, a user might access an application by requesting the general URL for a site: https://www.microsoft.com. The load balancer routes the request to a specific server, for example, server3.microsoft.com. ASP creates a new user session on that server. In the Session_OnStart procedure, the browser is redirected to the specified server:

  <% Response.Redirect("https://server3.microsoft.com/webapps/firstpage.asp") %>

The browser will request the specified page, and all subsequent requests will be routed to the same server as long as specific server names are not referenced in the original URLs.

Using Cookies

A cookie is a token that the Web server embeds in a user's Web browser to identify the user. The next time the same browser requests a page, it sends the cookie it received from the Web server. Cookies allow a set of information to be associated with a user. ASP scripts can both get and set the values of cookies by using the Response.Cookies Collection collection of the Response and Request objects.

Setting Cookies

To set the value of a cookie, use Response.Cookies. If the cookie does not already exist, Response.Cookies creates a new one. For example, to send a cookie named ("VisitorID") with an associated value ("49") to the browser, use the following command, which must appear on your Web page before the <HTML> tag:

  <% Response.Cookies("VisitorID") = 49 %>

If you want a cookie to be used only during the current user session, then sending the cookie to the browser is all you need to do. However, if you want to identify a user even after the user has stopped and restarted the browser, you must force the browser to store the cookie in a file on the client computer's hard disk. To save the cookie, use the Expires attribute for Response.Cookies and set the date to some date in the future:

  <%
  Response.Cookies("VisitorID") = 49 
  Response.Cookies("VisitorID").Expires = "December 31, 2001" 
%>

A cookie can have multiple values; such a cookie is called an indexed cookie. An indexed cookie value is assigned a key; you can set a particular cookie key value. For example:

  <% Response.Cookies("VisitorID")("49") = "Travel" %>

If an existing cookie has key values but Response.Cookies does not specify a key name, then the existing key values are deleted. Similarly, if an existing cookie does not have key values but Response.Cookies specifies key names and values, the existing value of the cookie is deleted and new key-value pairs are created.

Getting Cookies

To get the value of a cookie, use the Request.Cookies collection. For example, if the user HTTP request sets VisitorID=49, then the following statement retrieves the value 49:

  <%= Request.Cookies("VisitorID") %>

Similarly, to retrieve a key value from an indexed cookie, use the key name. For example, if a user's browser sends the following information in the HTTP request header:

Cookie: VisitorID=49=Travel

The following statement would then return the value Travel:

  <%= Request.Cookies("VisitorID")("49") %>

Each cookie stored by ASP on the user's Web browser contains path information. When the browser requests a file stored in the same location as the path specified in the cookie, the browser automatically forwards the cookie to the server. By default, cookie paths correspond to the name of the application containing the .asp file that originally generated the cookie. For example, if an .asp file, residing in an application called UserApplication, generates a cookie, then each time a user's Web browser retrieves any file residing in that application, the browser will forward the cookie, in addition to any other cookies containing the path /UserApplication.

To specify a path for a cookie other than the default application path, you can use the ASP Response.Cookies collection's Path attribute. For example, the following script assigns the path SalesApp/Customer/Profiles/ to a cookie called Purchases:

  <%
  Response.Cookies("Purchases") = "12" 
  Response.Cookies("Purchases").Expires = "January 1, 2001" 
  Response.Cookies("Purchases").Path = "/SalesApp/Customer/Profiles/"
%>

Whenever the Web browser containing the Purchases cookie requests a file residing in the path /SalesApp/Customer/Profiles/ or in any of it subdirectories, the browser forwards the cookie to the server.

Many Web browsers, including Microsoft Internet Explorer version4.0, or later, and Netscape browsers, preserve the case of the cookie path. This means that if the case of the path of a requested file differs from the case of the stored cookie path, the browser will not send the cookie to the server. For example, to ASP, the virtual directories /TRAVEL and /travel are the same ASP application, but to a browser that preserves the case of a URL, /TRAVEL and /travel are two different applications. Make sure all URLs to .asp files have the same case to ensure that the user's browser forwards stored cookies.

You can use the following statement to set the cookie path so that the user's Web browser will forward a cookie whenever the browser requests a file from your server, regardless of application or path:

  Response.Cookies("Purchases").Path = "/"

Note, however, that forwarding cookies to the server, without distinguishing between applications, raises a potential security concern if the cookies contain sensitive information that should not be accessible outside of a specific application.

Preserving State without Cookies

Not all browsers support cookies. Even with browsers that do support cookies, some users prefer to turn off cookie support. If your application needs to be responsive to browsers that don't support cookies, you cannot use ASP session management.

In this case, you must write your own mechanism to pass information from page to page in your application. There are two general ways to do this:

  • Add parameters to a URL's query string. For example:

    https://MyServer/MyApp/start.asp?name=Jeff
    

    Some browsers, however, will discard any explicit parameters passed in a query string if a form is submitted with the GET method.

  • Add hidden values to a form. For example, the following HTML form contains a hidden control, which does not appear on the actual form and remains invisible in the user's Web browser. The form passes a user identification value, in addition to the information supplied by the user, by using the HTTP POST method.

    <FORM METHOD="POST" ACTION="/scripts/inform.asp">
    <INPUT TYPE="text" NAME="city" VALUE="">
    <INPUT TYPE="text" NAME="country_region" VALUE ="">
    <INPUT TYPE="hidden" NAME="userid" VALUE= <%= UserIDNum(i) %>
    <INPUT TYPE="submit"  VALUE="Enter">
    
    

    This method requires all link destinations that pass user information to be coded as HTML forms.

If you are not using ASP session management, you should turn off session support for your application. When sessions are enabled, ASP sends a SessionID cookie to each browser that requests a page. To turn off session support, clear the Enable Session State check box on the Application Options property sheet in the Internet Information Services snap-in.

Sessionless ASP Pages

With ASP, you can also create sessionless pages which can be used to put off the creation of sessions tracking until needed.

Sessionless pages do not carry out the following:

  • Execute Session_OnStart procedures.
  • Send session ID cookies.
  • Create Session objects.
  • Access built-in Session objects or session scope objects created with the <OBJECT> tag.
  • Serialize execution with other session requests.

To configure an .asp file as sessionless, use the following:

  <%@ EnableSessionState=False %>

You should place this script as the first line in your .asp file, before any other scripts. The default, when this tag is omitted, enables session tracking.

Sessionless ASP pages can often improve the responsiveness of your server by eliminating potentially time consuming session activity. For example, consider the case of an ASP page containing two HTML frames: frames 1 and 2, both within one frameset. Frame 1 contains an .asp file that executes a complex script, while frame 2 contains a simpler .asp file. Because ASP executes session requests in sequential order, or serially, you will not be able to see the contents of frame 2 until the script in frame 1 has executed. However, if you make the .asp file for frame 1 sessionless, then ASP requests will no longer be serialized and the browser will render the contents of frame 2 before the contents of frame 1 have finished executing.

Unfortunately, the way in which multiple requests for different frames are processed ultimately depends on the configuration of the user's Web browser. Certain Web browsers may serialize requests despite the sessionless configuration of your .asp files.