How to cal Session_End() method when you store the Session state not in Inprc but StageServer, etc.

Reference:http://www.codeproject.com/KB/aspnet/SessionEndStatePersister.aspx
The Session_End event is a useful event which an be handled in Global.asax to perform any actions when a session ends, such as logging an activity to the database, cleaning up temporary session files, etc.

However, when using any kind of state management other than InProc (such as StateServer or SqlStateServer), the ASP.NET web application does not fire the Session_End event, and any code in this method will not be executed.

Some browsing around returned a couple of good articles. The article Page tracking in ASP.NET offers a similar solution, though is geared around page tracking whereas my requirement was simply to find an alternative to the Session_End event that would work with the ASP.NET StateServer.

There's another excellent article called Preventing Multiple Logins in ASP.NET This is where I got the idea of using the application cache with a sliding expiry to trigger an event when the session ends.

The SessionEndModule class hooks into the PreRequestHandlerExecute event and inserts/replaces an item in the application cache, with a sliding expiry equal to the session expiry, and a callback method to be called when the item is removed from the application cache. The key of the cache item is the SessionId, and the value is the value of the item in the session with the key set as the SessionObjectKey.

When the item expires and the callback method is called. The key, value and reason of the expired item is passed to this callback method. The key is the SessionId, the value is the value copied from the session, and the reason is why the item was removed from the cache (was it removed, expired, underused, or it's dependency changed).

The callback method then checks that the item was removed as a result of it expiring, wraps the values into a SessionEndEventArgs class (which exposes SessionId and SessionObject properties), and fires the SessionEnd event.


//Code
using  System;
using  System.Diagnostics;
using  System.IO;
using  System.Web;
using  System.Web.Caching;
using  System.Web.SessionState;

namespace  SessionTestWebApp
{
    
///   <summary>
    
///  When an ASP.NET State Server other than InProc, the Session_End event
    
///  does not get fired.  This is an HttpModule which uses some workarounds
    
///  and fires a static event when a session ends, with the value of a single
    
///  configurable session variable in the event arguments.
    
///   </summary>
     public   class  SessionEndModule : IHttpModule
    {
        
#region  Private Variables

        
private  HttpApplication m_HttpApplication;
        
private   static   string  m_SessionObjectKey;

        
#endregion

        
#region  Accessors

        
///   <summary>
        
///  This is the key of the item in the session which should be returned
        
///  in the SessionEnd event (as the SessionObject).
        
///   </summary>
        
///   <example>
        
///     If you're storing the user ID in the session, under a key called 'UserId'
        
///  and need to do something with it in the SessionEnd event, you would set
        
///  this to 'UserId', which would cause the value of the session key called
        
///  'UserId' to be returned.
        
///   </example>
         public   static   string  SessionObjectKey
        {
            
get
            {
                
return  m_SessionObjectKey;
            }
            
set
            {
                m_SessionObjectKey 
=  value;
            }
        }

        
#endregion

        
#region  IHttpModule Implementation

        
public   void  Init(HttpApplication context)
        {
            m_HttpApplication 
=  context;
            m_HttpApplication.PreRequestHandlerExecute 
+=   new  EventHandler(OnPreRequestHandlerExecute);
        }

        
public   void  Dispose()
        {
            
//  Do Nothing
        }

        
#endregion

        
#region  Events

        
///   <summary>
        
///  Event raised when the session ends
        
///   </summary>
         public   static   event  SessionEndEventHandler SessionEnd;

        
#endregion

        
private   void  OnPreRequestHandlerExecute( object  sender, EventArgs e)
        {
            
//  We only want to update the session when an ASPX page is being viewed
            
//  We're also doing this in the PreRequestHandler, as doing it elsewhere
            
//  (like the PostRequestHandler) can cause some strange behaviour.

            
if  (Path.GetExtension(m_HttpApplication.Context.Request.Path).ToLower()  ==   " .aspx " )
            {
                
//  Ensure we have a HttpContext
                 if  (HttpContext.Current  ==   null )
                {
                    Debug.WriteLine(
" No current http context " );
                    
return ;
                }

                
//  Get the current session
                HttpSessionState currentSession  =  HttpContext.Current.Session;

                
//  Ensure we have a current session
                 if  (currentSession  ==   null )
                {
                    Debug.WriteLine(
" No current session " );
                    
return ;
                }

                
//  Get the session timeout
                TimeSpan sessionTimeout  =   new  TimeSpan( 0 0 , currentSession.Timeout,  0 0 );

                
//  Get the object in the session we want to retrieve when the session times out
                 object  sessionObject  =  currentSession[SessionObjectKey];

                
//  Add the object to the cache with the current session id, and set a cache removal callback method
                HttpContext.Current.Cache.Insert(currentSession.SessionID, sessionObject,  null , DateTime.MaxValue, sessionTimeout, CacheItemPriority.NotRemovable,  new  CacheItemRemovedCallback(CacheItemRemovedCallbackMethod));
            }
        }

        
///   <summary>
        
///  This method is fired when an item is removed from the cache.  It is used to detect when a cache item
        
///  expires, indicating that the session has expired, and fires the SessionEnd event.
        
///   </summary>
         private   void  CacheItemRemovedCallbackMethod( string  key,  object  value, CacheItemRemovedReason reason)
        {
            
if  (reason  ==  CacheItemRemovedReason.Expired)
            {
                
if  (SessionEnd  !=   null )
                {
                    SessionEndedEventArgs e 
=   new  SessionEndedEventArgs(key, value);
                    SessionEnd(
this , e);
                }
            }
        }
    }

    
///   <summary>
    
///  Event handler for handling the SessionEnd event
    
///   </summary>
     public   delegate   void  SessionEndEventHandler( object  sender, SessionEndedEventArgs e);

    
///   <summary>
    
///  SessionEndedEventArgs for use in the SessionEnd event
    
///   </summary>
     public   class  SessionEndedEventArgs : EventArgs
    {
        
public   readonly   string  SessionId;
        
public   readonly   object  SessionObject;

        
public  SessionEndedEventArgs( string  sessionId,  object  sessionObject)
        {
            SessionId 
=  sessionId;
            SessionObject 
=  sessionObject;
        }
    }
}
//Web.config
< httpModules >
 
< add name = " SessionEndModule "  type = " SessionTestWebApp.Components.SessionEndModule, SessionTestWebApp " />
</ httpModules >

<!--  Use the state server (rather than InProc), and  set  the timeout to  1  minute  for  easier testing -->
< sessionState mode = " StateServer "  stateConnectionString = " tcpip=127.0.0.1:42424 "  timeout = " 1 "  cookieless = " false " />
//Global.asx
protected   void  Application_Start( object  sender, EventArgs e)
{
  
//  In our sample application, we want to use the value of Session["UserEmail"] when our session ends
  SessionEndModule.SessionObjectKey  =   " UserEmail " ;

  
//  Wire up the static 'SessionEnd' event handler
  SessionEndModule.SessionEnd  +=   new  SessionEndEventHandler(SessionTimoutModule_SessionEnd);
}
private   static   void  SessionTimoutModule_SessionEnd( object  sender, SessionEndedEventArgs e)
{
   Debug.WriteLine(
" SessionTimoutModule_SessionEnd : SessionId :  "   +  e.SessionId);

   
//  This will be the value in the session for the key specified in Application_Start
   
//  In this demonstration, we've set this to 'UserEmail', so it will be the value of Session["UserEmail"]
    object  sessionObject  =  e.SessionObject;
 
   
string  val  =  (sessionObject  ==   null ?   " [null] "  : sessionObject.ToString();
   Debug.WriteLine(
" Returned value:  "   +  val);
}
protected   void  Session_Start( object  sender, EventArgs e)
{
   Debug.WriteLine(
" Session started:  "   +  Session.SessionID);
 
   Session[
" UserId " =   new  Random().Next( 1 100 );
   Session[
" UserEmail " =   new  Random().Next( 100 1000 ).ToString()  +   " @domain.com " ;
 
   Debug.WriteLine(
" UserId:  "   +  Session[ " UserId " ].ToString()  +   " , UserEmail:  "   +  
                 Session[
" UserEmail " ].ToString());
}

你可能感兴趣的:(session)