ASP.net Session阻塞、Session鎖、MVC Action請求阻塞問題


會話Session

  • Session用於服務器端狀態管理,使用Session以後,每一個客戶端均可以將實際的數據保存在服務器上,對於每一個客戶端的數據,將會生成一個對應的惟一的key(保存在客戶端)。客戶端與服務器端就是經過這個key來確認客戶端的身份,一般這個key爲SessionID。
  • 通常狀況下,SessionID以Cookie的形式保存在瀏覽器中,在不使用Cookie的狀況下,也能夠將這個SessionID嵌入到訪問網頁的URL中。

服務器端Session

在頁面對象或者HttpContext對象中,都有一個名爲Session的屬性,在一次會話中,它們引用的都是同一個對象。javascript

public HttpSessionState Session { get; }

Session對象是HttpSessionState類的實例。Session是保存在服務器端的,對每一個登陸到網站的用戶都有一份,是獨有的,而其餘用戶沒法共享。html


那麼問題來了,來看看奇怪的阻塞。

咱們來看一個一需求: 須要實時的將服務器的運行狀態輸出到當前登錄的客戶端,創建長鏈接而且做實時輸出。 而後就有了下面這個Action。java

Boolean isOnline = true;
 
 public ActionResult Index()
 {
            #region 滾動條控制

            Response.Write("<html onclick=\"clearInterval(i_1);\" ondblclick =\"reInterval()\"><head><title>服務器實時監控</title></head>");
            Response.Write("<script type=\"text/javascript\">");
            Response.Write("function scrollWindow() { document.body.scrollTop = document.body.scrollHeight; }");
            Response.Write("function reInterval() { i_1 = setInterval('scrollWindow()', 50); }");
            Response.Write("i_1 = setInterval('scrollWindow()', 50);");
            Response.Write("scrollWindow();");
            Response.Write("</script> ");
            Response.Flush();

            #endregion
            
            Dictionary<int, string> dicColor = new Dictionary<int, string>() 
            {
                {0,"#0000FF"},          // 藍色
                {1,"#FF3333"},          // 紅色
                {2,"#FFFF00"},          // 黃色
                {3,"#FF3EFF"},
                {4,"#0000FF"},
                {5,"#0000FF"}
            };
            DebugCallback callback = new DebugCallback(delegate(int type, string str)
            {
                if (dicColor.ContainsKey(type))
                {
                    Response.Write("<span style = 'color:" + dicColor[type] + ";'>" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "--" + str + "</span>  <br />");
                }
                Response.Flush();
            });

            Log.AddCallBack(callback);

            while (isOnline)
            {
                try
                {
                    Response.Write("...<br>");
                    Response.Flush();
                }
                catch { }
                System.Threading.Thread.Sleep(1000);
                if (!Response.IsClientConnected)            // 鏈接關閉
                {
                    Log.RemoveCallBack(callback);
                    Response.Write("</html>");
                    break;
                }
            }
            return null;
        }
View Code

 


因爲這個Action是一個長鏈接,它不會斷開鏈接會一直處於請求的狀態,這個時候當咱們再請求同一個Session的其它的Action的時候,發現全部其它的Action都會處於Waiting狀態……好吧,明明是異步併發請求,爲什麼如今卻成了「單線程」工做了呢?很明顯有鎖。瀏覽器


緣由

  • HttpSessionState來自於HttpModule的SessionStateModule。在每次請求處理過程當中,HttpApplication的請求的處理管道中會檢查當前請求的處理程序是否實現了接口IRequiresSessionState,若是實現的話,那麼SessionStateModule將爲這個請求分配HttpSessionState。同時SessionStateModule還負責SessionID的生成、Cookieless會話管理、從外部狀態提供程序中檢索會話數據以及將數據綁定到請求的調用上下文。
  • 若是頁面請求設置一個讀取器鎖定,同一會話中同時處理的其餘請求將沒法更新會話狀態,可是至少能夠進行讀取。若是頁面請求爲會話狀態設置一個寫入鎖,那麼全部其餘頁面都被阻止,不管他們是否要讀取或寫入內容。例如,若是同時有兩段程序視圖在同一個Session中寫入內容,一段程序必須等到另外一段程序完成後才能寫入。在AJAX程序設計中,必須注意這種狀況的發生。

解決方法

對於Asp.net MVC:

能夠爲本Controller增長如下特性,可是本Controller都不能修改Session了,只能讀取服務器

[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]

 

對於Asp.net WebForm:

在Web.config 文件裏面添加併發

EnableSessionState="ReadOnly" // 僅僅加載那個阻塞頁面
相關文章
相關標籤/搜索