The HttpSessionState class provides a dictionary-based model of storing and retrieving session-state values. Unlike HttpApplicationState,
this class doesn’t expose its contents to all users operating on the
virtual directory at a given time. Only the requests that originate in
the context of the same session—that is, generated across multiple page
requests made by the same user—can access the session state. The session
state can be stored and published in a variety of ways, including in a
Web farm or Web garden scenario. By default, though, the session state
is held within the ASP.NET worker process.
Compared to Session,
the intrinsic object of ASP, the ASP.NET session state is nearly
identical in use, but it’s significantly richer in functionality and
radically different in architecture. In addition, it provides some
extremely handy facilities—such as support for cookieless browsers, Web
farms, and Web gardens—and the capability of being hosted by external
processes, including Microsoft SQL Server. In this way, ASP.NET session
management can provide an unprecedented level of robustness and
reliability.
Starting with ASP.NET 2.0, developers can create
custom data stores for session state. For example, if you need the
robustness that a database-oriented solution can guarantee but you work
with Oracle databases, you need not install SQL Server as well. By
writing a piece of additional code, you can support an Oracle session
data store while using the same Session semantics and classes.
The extensibility model for session state offers
two options: customizing bits and pieces of the existing ASP.NET session
state mechanism (for example, creating an Oracle session provider or a
module controlling the generation of the ID), and replacing the standard
session state HTTP module with a new one. The former option is easier
to implement but provides a limited set of features you can customize. The latter option is more complicated to code but provides the greatest flexibility.
The Session-State HTTP Module
Regardless of the internal implementation, the
programmer’s application programming interface (API) for session state
management is just one—the old acquaintance known as the Session object. It was a COM object in classic ASP that was instantiated in the asp.dll ISAPI extension and injected into the memory space of the ActiveX Scripting engine called to parse and process the .asp script. It is a collection object in ASP.NET, living behind the Session property of the Page class. The exact type is HttpSessionState; it’s a class that’s not further inheritable and that implements ICollection and IEnumerable.
An instance of this class is created during the startup of each request
that requires session support. The collection is filled with name/value
pairs read from the specified medium and attached to the context of the
request—the HttpContext class. The Page’s Session property just mirrors the Session property of the HttpContext class.
If developers can simply work with one object—the Session
object—regardless of other details, most of the credit goes to an HTTP
module that governs the process of retrieving and storing session state
with some help from special provider objects. The ASP.NET module in
charge of setting up the session state for each user connecting to an
application is an HTTP module named SessionStateModule. Structured after the IHttpModule interface, the SessionStateModule object provides session-state services for ASP.NET applications.
Although, as an HTTP module, it is required to supply a relatively simple programming interface—the IHttpModule interface contracts only for Init and Dispose methods—SessionStateModule
does perform a number of quite sophisticated tasks, most of which are
fundamental for the health and functionality of the Web application. The
session-state module is invoked during the setup of the HttpApplication
object that will process a given request and is responsible for either
generating or obtaining a unique session ID string and for storing and
retrieving state data from a state provider—for example, SQL Server or
the Web server’s memory.
State Client Managers
When invoked, the session-state HTTP module reads the settings in the <sessionState> section of the web.config
file and determines what the expected state client manager is for the
application. A state client manager is a component that takes care of
storing and retrieving data of all currently active sessions. The SessionStateModule component queries the state client manager to get the name/value pairs of a given session.
In
ASP.NET, there are four possibilities for working with the session
state. The session state can be stored locally in the ASP.NET worker
process; the session state can be maintained in an external, even
remote, process named aspnet_state.exe;
and the session state can be managed by SQL Server and stored in an ad
hoc database table. The fourth option entails you storing the sessions
in a custom component. Table 1 briefly discusses the various options.
Table 1. State Client Providers
Mode | Description |
---|
Custom | The values for all the sessions are stored in a custom data store. Not available in ASP.NET 1.x. |
InProc | The values for all the sessions are maintained as live objects in the memory of the ASP.NET worker process (aspnet_wp.exe or w3wp.exe in Microsoft Windows Server 2003 and beyond). This is the default option. |
Off | Session state is disabled, and no state client provider is active. |
SQLServer | The
values for all the sessions are serialized and stored in a SQL Server
table. The instance of SQL Server can run either locally or remotely. |
StateServer | The values for all the sessions are serialized and stored in the memory of a separate system process (aspnet_state.exe).
The process can also run on another machine. Session values are
deserialized into the session dictionary at the beginning of the
request. If the request completes successfully, state values are
serialized into the process memory and made available to other pages. |
The SessionStateMode enum type lists the available options for the state client provider. The InProc
option is by far the fastest possible in terms of access. However, bear
in mind that the more data you store in a session, the more memory is
consumed on the Web server, which increases the risk of performance
hits. If you plan to use any of the out-of-process solutions, the
possible impact of serialization and deserialization should be carefully
considered.
The session-state module determines the state provider to use based on what it reads out of the <sessionState> section of the web.config
file. Next, it instantiates and initializes the state provider for the
application. Each provider continues its own initialization, which is
quite different depending on the type. For example, the SQL Server state
manager opens a connection to the given database, whereas the
out-of-process manager checks the specified TCP port. The InProc state manager, on the other hand, stores a reference to the callback function that will be used to fire the Session_End event.
All state providers expose a common set of methods to communicate with the caller. The schema is outlined in Figure 11.
Note
All the actual state provider objects derive from a base class—SessionStateStoreProviderBase. In ASP.NET 1.x, on the other hand, all state providers implement a common interface, named IStateClientManager.
This interface has been lost in the transition to version 2.0, a victim
of the refactoring process and the advent of the provider model. However, the switch to base classes, from interfaces, is a pervasive design choice that affects the entire ASP.NET Framework. |
Creating the HttpSessionState Object
The state module is responsible for retrieving
and attaching the session state to the context of each request that runs
within the session. The session state is available only after the HttpApplication.AcquireRequestState event fires, and it gets irreversibly lost after the HttpApplication.ReleaseRequestState event. Subsequently, this means that no state is still available when Session_End fires.
The session module creates the HttpSessionState object for a request while processing the HttpApplication.AcquireRequestState event. At this time, the HttpSessionState
object—a sort of collection—is given its session ID and the session
dictionary. The session dictionary is the actual collection of state
values that pages will familiarly access through the Session property.
If a new session is being started, such a data
dictionary is simply a newly created empty object. If the module is
serving a request for an existing session, the data dictionary will be filled
by deserializing the contents supplied by the currently active session
state provider. At the end of the request, the current content of the
dictionary, as modified by the page request, is flushed back to the
state provider through a serialization step. The whole process is
depicted in Figure 2.
Synchronizing Access to the Session State
So when your Web page makes a call into the Session
property, it’s actually accessing a local, in-memory copy of the data.
What if other pages (in the same session) attempt to concurrently access
the session state? In that case, the current request might end up
working on inconsistent data or data that isn’t up to date.
To avoid that, the session state module
implements a reader/writer locking mechanism and queues the access to
state values. A page that has session-state write access will hold a
writer lock on the session until the request finishes. A page gains
write access to the session state by setting the EnableSessionState attribute on the @Page directive to true. A page that has session-state read access—for example, when the EnableSessionState attribute is set to ReadOnly—will hold a reader lock on the session until the request finishes.
If a page request sets a reader lock, other
concurrently running requests cannot update the session state but are
allowed to read. If a page request sets a writer lock on the session
state, all other pages are blocked regardless of whether they have to
read or write. For example, if two frames attempt to write to Session, one of them has to wait until the other finishes. Figure 3 shows the big picture.
Tip
Concurrent access to the
session state is not very common in reality. It might happen if you
have a multiframe page or if your users work with two copies of the same
page or multiple pages of the same application at the same time. It
also happens when you use session-enabled HTTP handlers to serve
embedded resources such as images or CSS files. By default, you are
protected against concurrent accesses. However, declaring the exact use
of the session state that a page is going to make (read/write, readonly,
or no use) is an excellent form of optimization. You do this through
the EnableSessionState attribute on the @Page directive. |
Properties of the HttpSessionState Class
The HttpSessionState class is defined in the System.Web.SessionState namespace. It is a generic collection class and implements the ICollection interface. The properties of the HttpSessionState class are listed in Table 2.
Table 2. HttpSessionState Properties
Property | Description |
---|
CodePage
Contents | Gets or sets the code page identifier for the current session.
Returns a reference to this object. Provided for ASP compatibility. |
CookieMode | Details the application’s configuration for cookieless sessions. Declared to be of type HttpCookieMode. (I’ll discuss this in more detail later.) Not available in ASP.NET 1.x. |
Count | Gets the number of items currently stored in the session state. |
IsCookieless | Indicates whether the session ID is embedded in the URL or stored in an HTTP cookie. It’s more specific than CookieMode. |
IsNewSession | Indicates whether the session was created with the current request. |
IsReadOnly | Indicates whether the session is read-only. The session is read-only if the EnableSessionState attribute on the @Page directive is set to the keyword ReadOnly. |
IsSynchronized | Returns false.
|
Item | Indexer property, provides read/write access to a session-state value. The value can be specified either by name or index. |
Keys | Gets a collection of the keys of all values stored in the session. |
LCID | Gets or sets the locale identifier (LCID) of the current session. |
Mode | Gets a value denoting the state client manager being used. Acceptable values are listed in Table 1. |
SessionID | Gets a string with the ID used to identify the session. |
StaticObjects | Gets a collection including all instances of all objects declared in global.asax using an <object> tag with the scope attribute set to Session. Note that you cannot add objects to this collection from within an ASP.NET application—that is, programmatically. |
SyncRoot | Returns a reference to this object.
|
Timeout | Gets or sets the minutes that the session module should wait between two successive requests before terminating the session. |
The HttpSessionState class is a normal collection class because it implements the ICollection
interface, but synchronization-wise it is a very special collection
class. As mentioned, the synchronization mechanism is implemented in the
SessionStateModule component, which guarantees that at most one thread will ever access the session state. However, because HttpSessionState implements the ICollection interface, it must provide an implementation for both IsSynchronized and SyncRoot. Note that IsSynchronized and SyncRoot
are collection-specific properties for synchronization and have nothing
to do with the session synchronization discussed previously. They refer
to the ability of the collection class (HttpSessionState in this case) to work in a synchronized manner. Technically speaking, the HttpSessionState is not synchronized, but access to session state is.
Methods of the HttpSessionState Class
Table 3 shows all the methods available in the HttpSessionState class. They mostly have to do with the typical operations on a collection. In this sense, the only exceptional method is Abandon, which causes the session to be canceled.
Table 3. HttpSessionState Methods
Method | Description |
---|
Abandon | Sets an internal flag that instructs the session module to cancel the current session. |
Add | Adds a new item to the session state. The value is boxed in an object type. |
Clear | Clears all values from the session state. |
CopyTo | Copies the collection of session-state values to a one-dimensional array, starting at the specified index in the array. |
GetEnumerator | Gets an enumerator to loop through all the values in the session. |
Remove | Deletes an item from the session-state collection. The item is identified by the key. |
RemoveAll | Calls Clear. |
RemoveAt | Deletes an item from the session-state collection. The item is identified by position. |
When running the procedure to terminate the
current request, the session-state module checks an internal flag to
verify whether the user ordered that the session be abandoned. If the
flag is set—that is, the Abandon method
was called—any response cookie is removed and the procedure to
terminate the session is begun. Notice, though, that this does not
necessarily mean that a Session_End event will fire.
First, the Session_End event fires only if the session mode is InProc;
second, the event does not fire if the session dictionary is empty and
no real session state exists for the application. In other words, at
least one request must have been completed for the Session_End to fire when the session is closed either naturally or after a call to Abandon.