ASPNET MVC源代碼來尋找解決方案由於在Action方法中可以調用BeginXxx方法我們在AsyncActionResult中只需保留Begin方法返回的IAsyncResult以及另一個對於EndXxx方法的引用在AsyncActionResult的ExecuteResult方法中將會保存這兩個對象以便在AsyncMvcHandler的EndProcessRequest方法中重新獲取並使用根據慣例我們還需要定義一個擴展方法方便開發人員在Action方法中返回一個AsyncActionResult具體實現非常容易在這裡就展示一下異步Action的編寫方式
[AsyncAction]
publicActionResultAsyncAction(AsyncCallbackasyncCallbackobjectasyncState)
{
SqlConnectionconn=newSqlConnection(;AsynchronousProcessing=true);
SqlCommandcmd=newSqlCommand(WAITFORDELAY::;conn); connOpen();
returnthisAsync( cmdBeginExecuteNonQuery(asyncCallbackasyncState) (ar)=>
{
intvalue=cmdEndExecuteNonQuery(ar);
connClose();
returnthisView();
});
}
至此似乎AsyncMvcHandler也無甚秘密可言了
publicclassAsyncMvcHandler:IHttpAsyncHandlerIRequiresSessionState
{
publicAsyncMvcHandler( Controllercontroller IControllerFactorycontrollerFactory RequestContextrequestContext)
{
thisController=controller;
thisControllerFactory=controllerFactory;
thisRequestContext=requestContext;
}
publicControllerController{get;privateset;
}
publicRequestContextRequestContext{get;privateset;
}
publicIControllerFactoryControllerFactory
{
get;privateset;
}
publicHttpContextContext{get;privateset;
}
publicIAsyncResultBeginProcessRequest( HttpContextcontext AsyncCallbackcb objectextraData)
{
thisContext=context;
thisControllerSetAsyncCallback(cb)SetAsyncState(extraData);
try
{
(thisControllerasIController)Execute(thisRequestContext);
returnthisControllerGetAsyncResult();
}
catch
{
thisControllerFactoryReleaseController(thisController);
throw;
}
}
publicvoidEndProcessRequest(IAsyncResultresult)
{
try
{
HttpContextCurrent=thisContext;
ActionResultactionResult=thisControllerGetAsyncEndDelegate()(result);
if(actionResult!=null)
{
actionResultExecuteResult(thisControllerControllerContext);
}
}
finally
{
thisControllerFactoryReleaseController(thisController);
}
}
}
在BeginProcessRequest方法中將保存當前Context——這點很重要HttpContextCurrent是基於 CallContext的一旦經過一次異步回調HttpContextCurrent就變成了null我們必須重設接著將接收到的 AsyncCallback和AsyncState保留並使用框架中現成的Execute方法執行控制器當Execute方法返回時一整個Action方法的調用流程已經結束這意味著其調用結果——即IAsyncResult和EndDelegate對象已經保留於是將IAsyncResult對象取出並返回至於EndProcessRequest方法只是將BeginProcessRequest方法中保存下來的EndDelegate取出調用把得到的ActionResult再執行一遍即可
以上的代碼只涉及到普通情況下的邏輯而在完整的代碼中還會包括對於Action方法被某個Filter終止或替換等特殊情況下的處理此外無論在BeginProcessRequest還是EndProcessRequest中都需要對異常進行合適地處理使得Controller Factory能夠及時地對Controller對象進行釋放
如果這個解決方案沒有缺陷那麼相信它已經被放入ASPNET MVC 中而輪不到我在這裡擴展一番了目前的這個解決方案至少有以下幾點不足
沒有嚴格遵守NET中的APM模式雖然不影響功能但這始終是一個遺憾
由於利用了框架中的現成功能所有的Filter只能運行在BeginXxx方法上
由於EndXxx方法和最終ActionResult的執行都沒有Filter支持因此如果在這個過程中拋出了異常將無法進入ASPNET MVC建議的異常處理功能中
根據ASPNET MVC框架的RoadmapASPNET MVC框架之後的版本中將會支持異步Action相信以上這些缺陷到時候都能被彌補不過這就需要大量的工作這只能交給ASPNET MVC團隊去慢慢執行了事實上您現在已經可以在ASPNET MVC源代碼的MvcFutures項目中找到異步Action處理的相關內容它添加了 IAsyncControllerAsyncControllerIAsyncActionInvokerAsyncControllerActionInvoker 等許多擴展雖說它們都繼承了現有的類但是與我之前的判斷相似如AsyncControllerActionInvoker幾乎完全重新實現了一遍ActionInvoker中的各種功能——我還沒有仔細閱讀代碼因此無法判斷出這種設計是否優秀只希望它能像ASPNET MVC本身那樣的簡單和優雅
我打算為現在的代碼的EndXxx方法也加上Filter支持我需要仔細閱讀ASPNET MVC源代碼來尋找解決方案希望它能夠成為ASPNET MVC正式支持異步Action之前較好的替代方案
From:http://tw.wingwit.com/Article/program/net/201311/12912.html