這個問題其實挺弔詭的,沒有什麼文件清楚的寫出來(該死的微軟)
要在IHttpModule中使用Session有非常多的限制:
1. 網路上眾說紛紜,有人說只在AcquireRequestState和PreRequestHandlerExecute兩個事件中,才有辦法使用Session,但也有人說http module根本沒辦法使用session,造成不少困擾。
2. 經測試,即使是在上述兩個事件中,HttpApplication.Context.Session依然為null,我的猜測是這樣的方法只適用於.aspx之類的http request,其餘一律行不通。(我發的http request是抓.png或是manifest這類的行為)
最後採用的解法是:
http://forums.asp.net/t/1098574.aspx/1
我看不太懂裡面針對handler物件繞來繞去的原因是什麼,只大概猜說是要自己宣告一個Handler類別,產生handler物件,然後用原本的Application.Context.Handler傳進來,藉此啟動SessionStateModule,讓SessionState成為avaliable狀態。
以下只擷取相關部分,RequestBegin之類的事件省略,
Code snippet:
public void Init(HttpApplication application)
{
// following two event handler are both required
application.PostAcquireRequestState += new EventHandler(OnPostAcquireRequestState);
application.PostMapRequestHandler += new EventHandler(OnPostMapRequestHandler);
}
/**
* for the usage of SessionState, replace the original handler with ours, force SessionState to be valiable
**/
public void OnPostMapRequestHandler(Object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
if (application.Context.Handler is IReadOnlySessionState || application.Context.Handler is IRequiresSessionState)
{
// no need to replace the original handler
return;
}
// swap the original handler
application.Context.Handler = new TempHandler(application.Context.Handler);
}
public void OnPostAcquireRequestState(Object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
TempHandler handler = HttpContext.Current.Handler as TempHandler;
if (handler != null)
{
HttpContext.Current.Handler = handler.myHandler;
}
// from this moment, SessionState is valiable
HttpSessionState session = application.Context.Session;
}
/**
* A temp handler used to force the SessionStateModule to load session state
**/
public class TempHandler : IHttpHandler, IRequiresSessionState
{
internal readonly IHttpHandler myHandler; // store original application context handler
public TempHandler(IHttpHandler originalhttpHandler)
{
this.myHandler = originalhttpHandler;
}
public void ProcessRequest(HttpContext context)
{
throw new InvalidOperationException("InvalidOperationException");
}
public bool IsReusable
{
get { return false; }
}
}
另外,module類別除了繼承IHttpModule以外,必須再繼承IRequiresSessionState。
Anyway,這個方法讓我成功取到Session.SessionID,原理之後再慢慢思考。
沒有留言:
張貼留言