2011-01-31 98 views
0

我想爲由AsyncController實現的長時間運行的請求提供進度監視機制。一個網頁所調用(通過JQuery $.post)下面控制器上的異步StartTask動作...通過AJAX調用的控制器之間的共享會話狀態訪問

[NoAsyncTimeout] 
public class TaskController: AsyncController 
{ 
    [HttpPost] 
    public void StartTaskAsync() 
    { 
     AsyncManager.OutstandingOperations.Increment(); 
     Session["progress"] = "in progress"; 
     Task.Factory.StartNew(DoIt); 
    } 

    public ActionResult StartTaskCompleted() 
    { 
     return Json(new {redirectUrl = Url.Action("TaskComplete", "First")}); 
    } 

    private void DoIt() 
    { 
     try 
     { 
     // Long-running stuff takes place here, including updating 
     // Session["progress"]. 
     } 
     finally 
     { 
     AsyncManager.OutstandingOperations.Decrement(); 
     } 
    } 
} 

同一網頁建立一個2秒定時器(經由window.setInterval)調用下面的控制器(通過JQuery $.getJSON)已只讀到會話訪問...

[SessionState(SessionStateBehavior.ReadOnly)] 
public class ProgressController: Controller 
{ 
    [HttpGet] 
    public ActionResult Current() 
    { 
     var data = Session["progress"]; 
     return Json(data, JsonRequestBehavior.AllowGet); 
    } 
} 

後的getJSON返回調用的函數更新一個DIV,顯示當前的進度。最終,進程將在會話中由'長期運行的東西在這裏'代碼進行更新,但由於它是對ProgressController.Current()的調用,因此在會話中找不到任何數據並始終返回null。

我曾經假設從同一個瀏覽器發送到同一個IIS服務器的JQuery AJAX請求最終會以相同的會話結束,但似乎沒有。我是否需要在這些$ .post和$ .getJSON調用上顯式設置ASP.NET會話密鑰?或者是不可能以這種方式在控制器之間共享會話狀態(即使擁有R/O訪問權限)(我可以回到具有應用程序狀態和GUID的稍微黑客解決方案)。

回答

0

這是正常行爲。您的StartTask操作會阻止,直到完成。直到DoIt方法執行完畢,它纔會返回任何響應。我想這就是爲什麼你用AJAX $.post來調用它。問題是,雖然此方法運行並寫入會話,並且來自同一會話的所有其他請求將由ASP.NET引擎排隊。您無法同時寫入和讀取會話。您將不得不爲會話以外的進度數據找到另一個線程安全存儲。

+0

StartTask動作是否真的阻止?我認爲StartTaskAsync方法返回(我認爲這是我在調試器中觀察到的,將再次嘗試)並且ASP.NET工作線程返回到池,直到收到AsyncManager.OutstandingOperations.Decrement()調用(儘管如何ASP.NET MVC將調用Decrement()的線程與我不確定的相應XxxCompleted()動作方法相關聯。 StartTaskAsync不會阻止來自同一瀏覽器實例的對ProgressController.Current()的調用,只是ProgressController.Current()看不到相同的會話。 – 2011-01-31 21:35:08