[转]ASP.NET HttpModule for handling session end with StateServer
2009-03-10 09:25
891 查看
from:http://www.codeproject.com/KB/aspnet/SessionEndStatePersister.aspx
Introduction
TheSession_Endevent 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
StateServeror
SqlStateServer), the ASP.NET web application does not fire the
Session_Endevent, and any code in this method will not be executed.
Background
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 theSession_Endevent 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.
How it works
TheSessionEndModuleclass hooks into the
PreRequestHandlerExecuteevent 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
SessionEndEventArgsclass (which exposes
SessionIdand
SessionObjectproperties), and fires the SessionEndevent.
Using the code
The code consists of aHttpModulecalled
SessionEndModule, which needs to be included in the project via the web.config file. It exposes a static property named
SessionObjectKeyand a static event named
SessionEndwhich will be fired when a session ends. The value of the
SessionObjectKeywill be returned in the event arguments for the SessionEndevent.
First lets set up web.config
Collapse
Copy Code
<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"/>
Then we need set up Global.asax
Collapse
Copy Code
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);
}
Then we need to create our event handler method for the
SessionEndevent:
Collapse
Copy Code
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);
}
In this demo, lets also wire up the
Session_Startand put some test data in the session
Collapse
Copy Code
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()); }
Testing the code
Start this project in debug mode and keep an eye on the output window. When the session starts, the session contents will populated with a randomUserIdand
UserEmail. The session will end after approximately 1 minute, and fire the SessionEndevent, which will execute the
SessionTimoutModule_SessionEndmethod and print the
SessionIdof the session that ended and the
UserEmailit contained.
Returning more than one session value
TheHttpModule.SessionEndevent only supports returning the value of a single session variable. If you need to return more than one value, the easiest way is to create a serializable class, with properties for all your values, and store that in the session instead.
For example:
Collapse
Copy Code
[Serializable]
public class SessionInfo
{
public string UserId;
public string UserName;
public string UserEmail;
}
SessionInfosessionInfo = new SessionInfo();
sessionInfo.UserId= 10;
sessionInfo.UserName = "Bob Jones";
sessionInfo.UserEmail= "bobjones@company.com";
Session["SessionInfo"] = sessionInfo;
In Global.asax, you would then set the SessionObjectKeyto 'SessionInfo':
Collapse
Copy Code
SessionEndModule.SessionObjectKey= "SessionInfo";
You can then access this in the SessionEndevent:
Collapse
Copy Code
private static void SessionTimoutModule_SessionEnd(object sender, SessionEndedEventArgs e)
{
Debug.WriteLine("SessionTimoutModule_SessionEnd: SessionId: " + e.SessionId);
SessionInfosessionInfo = e.SessionObjectas SessionInfo;
if (sessionObject == null)
{
Debug.WriteLine("Returned value is null");
}
else
{
Debug.WriteLine("Returned values - UserId: " + sessionInfo.UserId+ ", UserName: " +
sessionInfo.UserName + ", UserEmail: " + sessionInfo.UserEmail);
}
}
Known limitations
As the module hooks into thePreRequestHandlerevent, the value of the
SessionObjectKeystored in the application cache before the page executes. This means that if you change the session variable being returned by the module in the
SessionEndevent (or the
SessionInfoobject) on a page, and then the session times out, the
SessionEndevent will contain the old value. It's possible to change this to use the
PostRequestHandlerevent, though I've experienced some strange behaviour with this, especially when using Response.TransmitFile.
This code also won't work on scenerarios where you are using a server farm. In the article 'Preventing Multiple Logins in ASP.NET', Peter Bromberg discusses this problem in more depth and offers some ideas for working around this.
History
Version 1.0 - 02 November 2007License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)About the Author
Munsifali Rashid | I'm a freelance web developer with 7+ years experience developing solutions using Microsoft technologies. Originally from London (UK) but now living in Orlando, FL, I'm currently working on various projects for numerous digital agencies across the globe, providing them with development and consulting services. My website and blog are at http://www.mlogix-inc.com/
|
相关文章推荐
- using sql server or sql azure for session state store in asp.net
- mod_aspdotnet module for Apache HTTP Server 2.x(APACHE集成DONET服务)
- Using SQL Server for asp.net session state
- Asp.Net 中使用HttpModule 做Session验证
- ASP.NET 使用mode=”InProc”方式保存Session老是丢失,无奈改成StateServer 模式。
- ASP.NET存储Session的StateServer
- An IP Address Blocking HttpModule for ASP.NET
- ASP.NET Session State Partitioning using State Server Load Balancing
- Session state has been disabled for ASP.NET.
- IIS安全工具UrlScan介绍 ASP.NET 两种超强SQL 注入免费解决方案( 基于IIS,使用免费工具) 批改或隐藏IIS7.5的Server头信息 移除X-Powered-By,MVC,ASP.NET_SessionId 的 HTTP头或者cookie名称
- asp.net session共享(通过StateServer方式)
- http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application
- 从ASP.NET 会话状态谈IReadOnlySessionState,IHttpSessionState,IRequiresSessionState
- (asp.net session总为null得到解决)了解IHttpModule接口事件执行顺便 获取Session 和SQL
- ASP.NET 使用mode=”InProc”方式保存Session老是丢失,无奈改成StateServer 模式。
- ASP.NET sessionState设置Mode为StateServer,报出Internal Server Error
- ASP.NET 使用mode=”InProc”方式保存Session老是丢失,无奈改成StateServer 模式。
- (asp.net session总为null得到解决)了解IHttpModule接口事件执行顺便 获取Session 和SQL
- 说说Asp.net的StateServer和Session共享
- asp.net基于StateServer的二级域名共享session