SessionStateUtility Class
Provides helper methods used by session-state modules and session-state store providers to manage session information for an ASP.NET application. This class cannot be inherited.
Assembly: System.Web (in System.Web.dll)
The SessionStateUtility class provides static helper methods that are used by a session-state module or a session-state store provider. Application developers will not need to call these methods from their code.
The following table describes the ways the session-state module and session-state store provider use the methods.
|
Method |
Use |
|---|---|
|
Can be used by custom session-state modules to either retrieve session information for an existing session or create session information for a new session. |
|
|
AddHttpSessionStateToContext method |
Called by the session-state module to add the session data to the current HttpContext and make it available to application code through the Session property. |
|
Called by the session-state module during the ReleaseRequestState or EndRequest events at the end of a request, to clear session data from the current HttpContext. |
|
|
GetSessionStaticObjects method |
Called by the session-state module to get a reference to the StaticObjects collection based on objects defined in the Global.asax file. The HttpStaticObjectsCollection collection returned is included with the session data added to the current HttpContext. |
Session data is passed to and retrieved from the current HttpContext as an HttpSessionStateContainer object or any valid implementation of the IHttpSessionState interface.
For information about implementing a session-state store provider, see Implementing a Session-State Store Provider.
The following code example shows a custom session-state module implementation that stores session information in memory using a Hashtable. The module uses the SessionStateUtility class to reference the current HttpContext and SessionIDManager, retrieve the current HttpStaticObjectsCollection, and raise the Session_OnEnd event defined in the Global.asax file for the ASP.NET application. This application does not prevent simultaneous Web requests from using the same session identifier.
using System; using System.Web; using System.Web.SessionState; using System.Collections; using System.Threading; using System.Web.Configuration; using System.Configuration; namespace Samples.AspNet.SessionState { public sealed class MySessionStateModule : IHttpModule, IDisposable { private Hashtable pSessionItems = new Hashtable(); private Timer pTimer; private int pTimerSeconds = 10; private bool pInitialized = false; private int pTimeout; private HttpCookieMode pCookieMode = HttpCookieMode.UseCookies; private ReaderWriterLock pHashtableLock = new ReaderWriterLock(); private ISessionIDManager pSessionIDManager; private SessionStateSection pConfig; // The SessionItem class is used to store data for a particular session along with // an expiration date and time. SessionItem objects are added to the local Hashtable // in the OnReleaseRequestState event handler and retrieved from the local Hashtable // in the OnAcquireRequestState event handler. The ExpireCallback method is called // periodically by the local Timer to check for all expired SessionItem objects in the // local Hashtable and remove them. private class SessionItem { internal SessionStateItemCollection Items; internal HttpStaticObjectsCollection StaticObjects; internal DateTime Expires; } // // IHttpModule.Init // public void Init(HttpApplication app) { // Add event handlers. app.AcquireRequestState += new EventHandler(this.OnAcquireRequestState); app.ReleaseRequestState += new EventHandler(this.OnReleaseRequestState); // Create a SessionIDManager. pSessionIDManager = new SessionIDManager(); pSessionIDManager.Initialize(); // If not already initialized, initialize timer and configuration. if (!pInitialized) { lock (typeof(MySessionStateModule)) { if (!pInitialized) { // Create a Timer to invoke the ExpireCallback method based on // the pTimerSeconds value (e.g. every 10 seconds). pTimer = new Timer(new TimerCallback(this.ExpireCallback), null, 0, pTimerSeconds * 1000); // Get the configuration section and set timeout and CookieMode values. Configuration cfg = WebConfigurationManager.OpenWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath); pConfig = (SessionStateSection)cfg.GetSection("system.web/sessionState"); pTimeout = (int)pConfig.Timeout.TotalMinutes; pCookieMode = pConfig.Cookieless; pInitialized = true; } } } } // // IHttpModule.Dispose // public void Dispose() { if (pTimer != null) { this.pTimer.Dispose(); ((IDisposable)pTimer).Dispose(); } } // // Called periodically by the Timer created in the Init method to check for // expired sessions and remove expired data. // void ExpireCallback(object state) { try { pHashtableLock.AcquireWriterLock(Int32.MaxValue); this.RemoveExpiredSessionData(); } finally { pHashtableLock.ReleaseWriterLock(); } } // // Recursivly remove expired session data from session collection. // private void RemoveExpiredSessionData() { string sessionID; foreach (DictionaryEntry entry in pSessionItems) { SessionItem item = (SessionItem)entry.Value; if ( DateTime.Compare(item.Expires, DateTime.Now)<=0 ) { sessionID = entry.Key.ToString(); pSessionItems.Remove(entry.Key); HttpSessionStateContainer stateProvider = new HttpSessionStateContainer(sessionID, item.Items, item.StaticObjects, pTimeout, false, pCookieMode, SessionStateMode.Custom, false); SessionStateUtility.RaiseSessionEnd(stateProvider, this, EventArgs.Empty); this.RemoveExpiredSessionData(); break; } } } // // Event handler for HttpApplication.AcquireRequestState // private void OnAcquireRequestState(object source, EventArgs args) { HttpApplication app = (HttpApplication)source; HttpContext context = app.Context; bool isNew = false; string sessionID; SessionItem sessionData = null; bool supportSessionIDReissue = true; pSessionIDManager.InitializeRequest(context, false, out supportSessionIDReissue); sessionID = pSessionIDManager.GetSessionID(context); if (sessionID != null) { try { pHashtableLock.AcquireReaderLock(Int32.MaxValue); sessionData = (SessionItem)pSessionItems[sessionID]; if (sessionData != null) sessionData.Expires = DateTime.Now.AddMinutes(pTimeout); } finally { pHashtableLock.ReleaseReaderLock(); } } else { bool redirected, cookieAdded; sessionID = pSessionIDManager.CreateSessionID(context); pSessionIDManager.SaveSessionID(context, sessionID, out redirected, out cookieAdded); if (redirected) return; } if (sessionData == null) { // Identify the session as a new session state instance. Create a new SessionItem // and add it to the local Hashtable. isNew = true; sessionData = new SessionItem(); sessionData.Items = new SessionStateItemCollection(); sessionData.StaticObjects = SessionStateUtility.GetSessionStaticObjects(context); sessionData.Expires = DateTime.Now.AddMinutes(pTimeout); try { pHashtableLock.AcquireWriterLock(Int32.MaxValue); pSessionItems[sessionID] = sessionData; } finally { pHashtableLock.ReleaseWriterLock(); } } // Add the session data to the current HttpContext. SessionStateUtility.AddHttpSessionStateToContext(context, new HttpSessionStateContainer(sessionID, sessionData.Items, sessionData.StaticObjects, pTimeout, isNew, pCookieMode, SessionStateMode.Custom, false)); // Execute the Session_OnStart event for a new session. if (isNew && Start != null) { Start(this, EventArgs.Empty); } } // // Event for Session_OnStart event in the Global.asax file. // public event EventHandler Start; // // Event handler for HttpApplication.ReleaseRequestState // private void OnReleaseRequestState(object source, EventArgs args) { HttpApplication app = (HttpApplication)source; HttpContext context = app.Context; string sessionID; // Read the session state from the context HttpSessionStateContainer stateProvider = (HttpSessionStateContainer)(SessionStateUtility.GetHttpSessionStateFromContext(context)); // If Session.Abandon() was called, remove the session data from the local Hashtable // and execute the Session_OnEnd event from the Global.asax file. if (stateProvider.IsAbandoned) { try { pHashtableLock.AcquireWriterLock(Int32.MaxValue); sessionID = pSessionIDManager.GetSessionID(context); pSessionItems.Remove(sessionID); } finally { pHashtableLock.ReleaseWriterLock(); } SessionStateUtility.RaiseSessionEnd(stateProvider, this, EventArgs.Empty); } SessionStateUtility.RemoveHttpSessionStateFromContext(context); } } }
To use this custom session-state module in an ASP.NET application, you can replace the existing SessionStateModule reference in the Web.config file, as shown in the following example.
<configuration>
<system.web>
<httpModules>
<remove name="Session" />
<add name="Session"
type="Samples.AspNet.SessionState.MySessionStateModule" />
</httpModules>
</system.web>
</configuration>
-
AspNetHostingPermission
for using the SessionStateUtility class in a hosted environment. Demand value: LinkDemand. Permission value: Minimal.
Windows 7, Windows Vista, Windows XP SP2, Windows XP Media Center Edition, Windows XP Professional x64 Edition, Windows XP Starter Edition, Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, Windows Server 2000 SP4, Windows Millennium Edition, Windows 98
The .NET Framework and .NET Compact Framework do not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.
One thing to be aware of is that the example implementation on this page is not production ready. One example of this is the use of an instance variable to hold the Hashtable containing the session data. When multiple requests are processed simultaneously, the server creates more than one instance of the SessionStateModule class. Thus, if two requests are processed by two threads with each thread holding its own instance of this class, each instance will have one session's data. Whether the next request is processed with the instance that contains its session data is a 50-50 proposition.
One option is to create your own class (that wraps a Dictionary) to serve as the data store for holding the session data instead of using a Hashtable directly. A good option for your class would be to create a singleton. That way all the session data is stored in one instance of the class. A singleton is slightly better than a static class in this case because you'll need to hold a reference to the Timer class (to remove expired sessions) in your data store class. If the application releases its reference to your data store class instance (making it eligible for garbage collection), then the timer will be eligible for garbage collection since the only reference to it was from your instance. If the timer were referenced by a static variable (i.e, class variable), I think it would run until the entire application was stopped since I don't think .Net normally unloads class definitions.
- 7/8/2008
- John M Paliwoda
Thus, in the scenario where an application has a logout function that includes abandoning the session and transferring the user to another page (e.g., the login page), the session will not be removed. One way around this problem is to add a method to your SessionStateModule class (see RemoveSession method below) that removes the session and a utility method to call it (see AbandonSession below). If you are using .Net 3.5, you can add the AbandonSession method as an extension method of the HttpSessionState class (the class exposed by the aspx page's Session property) so users can call it similarly to calling the Abandon method (i.e., Session.AbandonSession()).
public void RemoveSession(HttpContext context) {
try {
pHashtableLock.AcquireWriterLock(Int32.MaxValue);
sessionID = pSessionIDManager.GetSessionID(context);
pSessionItems.Remove(sessionID);
} finally {
pHashtableLock.ReleaseWriterLock();
}
}
public static void AbandonSession(HttpContext context) {
IHttpModule httpModule = context.ApplicationInstance.Modules["Session"];
MySessionStateModule sessionStateModule = (MySessionStateModule)httpModule;
sessionStateModule.RemoveSession(context);
}
- 7/3/2008
- John M Paliwoda
- 7/3/2008
- John M Paliwoda