2013-12-16 47 views
1

我在現有的ASP.NET項目中實現了一個自定義web處理程序(ashx)頁面,該頁面使用Session對象來知道哪個用戶是請求頁面。網頁處理程序的工作原理除了一個主要缺點。 Session對象不可用於我的WebSocket處理程序任務。如何從WebSocket請求獲取ASP.NET Session對象?

我試過打電話HttpContext.Current.Session但它是空的。

有什麼建議嗎?

更新

感謝卡爾·安德森的回答,我能夠做一些頭部的方式,但問題仍然有效。我在處理程序代碼如下:

public class WSHandler : IHttpHandler, IRequiresSessionState 
{ 
    public void ProcessRequest(HttpContext context) 
    { 
     if (context.IsWebSocketRequest) 
     { 
      string s = context.Session["UserName"]; // This works now! 
      context.AcceptWebSocketRequest(ProcessWebSocket); 
     } 
    } 

    public bool IsReusable { get { return false; } } 

    private async Task ProcessWebSocket(AspNetWebSocketContext context) 
    { 
     string s = HttpContext.Current.Session["UserName"]; // This still doesn't. The Session property is null 
     ... 
    } 
} 

回答

0

我能夠想到的最好的方法是創建一個調用Web表單來獲取/設置會話數據的方法。我知道這不是非常有效,但我沒有看到任何其他方式來做到這一點。

編輯: 爲了這個工作,你需要在Web.Config文件中啓用Cookieless會話。這對於大多數網站來說可能是一個很大的安全風險,所以請記住實施邏輯以防止會話劫持!我目前使用IP驗證以及瀏覽器指紋檢查。

我創造,我在我的WebSocket處理器(WSHandler.ashx)使用類:

public class SessionData 
{ 
    AspNetWebSocketContext _WebSocketContext = null; 

    public SessionData(AspNetWebSocketContext WebSocketContext) 
    { 
     _WebSocketContext = WebSocketContext; 
    } 

    public string GetSessionValue(string name) 
    { 
     string value = ""; 

     using (WebClient wc = new WebClient()) 
     { 
      string Url = _WebSocketContext.Origin + _WebSocketContext.RawUrl.Replace("WSHandler.ashx", "UpdateSession.aspx"); 
      Url += "?a=1"; 
      Url += "&n=" + name; 
      value = wc.DownloadString(Url); 
     } 

     return value; 
    } 

    public void PutSessionValue(string name, string value) 
    { 
     using (WebClient wc = new WebClient()) 
     { 
      string Url = _WebSocketContext.Origin + _WebSocketContext.RawUrl.Replace("WSHandler.ashx", "UpdateSession.aspx"); 
      Url += "?a=2"; 
      Url += "&n=" + name; 
      Url += "&v=" + value; 
      wc.DownloadString(Url); 
     } 
    } 

} 

下面是Web表單UpdateSession.aspx形式:

public partial class UpdateSession : System.Web.UI.Page 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     string action = Page.Request.QueryString["a"]; 
     string name = Page.Request.QueryString["n"]; 
     string value = Page.Request.QueryString["v"]; 

     Page.Response.Clear(); 

     if (string.IsNullOrEmpty(name) == true) 
     { 
      return; 
     } 

     switch (action) 
     { 
      case "1": 
       if (Session[name] != null) 
       { 
        Page.Response.Write(Session[name].ToString()); 
       } 
       break; 

      case "2": 
       Session[name] = value; 
       break; 
     } 

     Page.Response.End(); 

    } 
} 
1

如果您只需要從Session對象讀取,那麼你需要在你的HTTP處理程序代碼來實現IReadOnlySessionState,像這樣:

public class YourHandler : IHttpHandler, IReadOnlySessionState 
{ 
    public void ProcessRequest(HttpContext theContext) 
    { 
     theContext.Response.Write(theContext.Session["YOUR_VALUE_HERE"]); 
    } 

    public bool IsReusable { get { return true; } } 
} 

如果您希望能夠讀取和寫入Session對象,則需要在HTTP處理程序代碼中實現IRequiresSessionState

+0

謝謝你把我在寫軌道上。我現在可以從'ProcessRequest'方法訪問Session對象。然而,我的'AcceptWebSocketRequest'任務沒有可用的會話,這是我需要它。我會將我的代碼添加到我原來的問題中。 – vbguyny

1

會話是故意不提供給WebSocket處理循環,因爲會話有一個默認的兩分鐘超時和WebSocket連接理論上可以永久持續。

如果您需要從Session中讀取數據,請提前閱讀各個對象(在主ProcessRequest方法中),並將其鬆動到某處,如在私人領域中。如果您需要將數據寫回Session,則需要使用其他機制(如實際的數據庫表),而不是使用Session本身。

+0

我認爲你的意思是說20分鐘的超時時間,而不是2分鐘;) 但是,你確實是一個很好的觀點。但是我打算讓Session對象變得很髒,如果有來自websocket的活動,以便用戶的會話不會過期。 – vbguyny

+1

@vbguyny不,我的意思是兩分鐘。會話對象不是線程安全的,所以ASP.NET運行時序列化訪問這些對象。延遲取決於這些Session對象的請求,直到對象解鎖。這種鎖定機制有兩分鐘的超時時間,並且長時間的WebSocket請求會在超時之後很好地發揮作用。最終的結果是一個損壞的Session對象,因爲多個線程會試圖同時訪問它。因此我們不會在WebSocket管道中提供它。 – Levi

+0

我明白了。我超時困惑與過期。這是一個有趣的問題。我將需要驗證。 – vbguyny

相關問題