ASP. net mvc source code to find a solution. Because the BeginXxx method can be called in the Action method, we only need to retain the IAsyncResult returned by the Begin method in AsyncActionResult, and another reference to the EndXxx method. The two objects will be saved in the ExecuteResult method of AsyncActionResult to be retrieved and used again in the EndProcessRequest method of AsyncMvcHandler. According to the "Convention", we also need to define an extension method so that developers can return an AsyncActionResult in the Action method. The specific implementation is very easy. Here we will show how to write asynchronous actions:
- [AsyncAction]
- publicActionResultAsyncAction(AsyncCallbackasyncCallback,objectasyncState)
- {
- SqlConnectionconn=newSqlConnection("...;AsynchronousProcessing=true");
- SqlCommandcmd=newSqlCommand("WAITFORDELAY'00:00:03';",conn);
- conn.Open();
-
- returnthis.Async(
- cmd.BeginExecuteNonQuery(asyncCallback,asyncState),
- (ar)=>
- {
- intvalue=cmd.EndExecuteNonQuery(ar);
- conn.Close();
- returnthis.View();
- });
- }
At this point, it seems that AsyncMvcHandler has no secret at all:
- publicclassAsyncMvcHandler:IHttpAsyncHandler,IRequiresSessionState
- {
- publicAsyncMvcHandler(
- Controllercontroller,
- IControllerFactorycontrollerFactory,
- RequestContextrequestContext)
- {
- this.Controller=controller;
- this.ControllerFactory=controllerFactory;
- this.RequestContext=requestContext;
- }
-
- publicControllerController{get;privateset;}
- publicRequestContextRequestContext{get;privateset;}
- publicIControllerFactoryControllerFactory{get;privateset;}
- publicHttpContextContext{get;privateset;}
-
- publicIAsyncResultBeginProcessRequest(
- HttpContextcontext,
- AsyncCallbackcb,
- objectextraData)
- {
- this.Context=context;
- this.Controller.SetAsyncCallback(cb).SetAsyncState(extraData);
-
- try
- {
- (this.ControllerasIController).Execute(this.RequestContext);
- returnthis.Controller.GetAsyncResult();
- }
- catch
- {
- this.ControllerFactory.ReleaseController(this.Controller);
- throw;
- }
- }
-
- publicvoidEndProcessRequest(IAsyncResultresult)
- {
- try
- {
- HttpContext.Current=this.Context;
- ActionResultactionResult=this.Controller.GetAsyncEndDelegate()(result);
- if(actionResult!=null)
- {
- actionResult.ExecuteResult(this.Controller.ControllerContext);
- }
- }
- finally
- {
- this.ControllerFactory.ReleaseController(this.Controller);
- }
- }
- }
It is important to save the Current Context in the BeginProcessRequest method. HttpContext. Current is based on CallContext. Once an asynchronous callback HttpContext. Current becomes null, it must be reset. The received AsyncCallback and AsyncState are retained, and the Controller is executed using the ready-made Execute method in the framework. When the Execute method returns, the call process of the entire Action method is completed, which means that the call result-IAsyncResult and EndDelegate objects have been retained. Therefore, the IAsyncResult object is taken out and returned. For the EndProcessRequest method, retrieve the EndDelegate saved in the BeginProcessRequest method, call it, and execute the obtained ActionResult again.
The above Code only involves the logic in general circumstances, and the complete code will also include the processing of Action methods in special circumstances such as being terminated or replaced by a Filter. In addition, exceptions must be properly handled in both BeginProcessRequest and EndProcessRequest, so that the Controller Factory can release Controller objects in a timely manner.
If this solution has no defects, I believe it has been put into ASP. net mvc 1.0, and I will not extend it here. The current solution has at least the following shortcomings:
The APM mode in. NET is not strictly followed. Although the function is not affected, it is always a pity.
Because of the ready-made functions in the framework, all filters can only run on the BeginXxx method.
Because the execution of the EndXxx method and the final ActionResult does not support Filter, if an exception is thrown during this process, the exception processing function recommended by ASP. net mvc cannot be entered.
According to Roadmap of ASP. net mvc Framework, asynchronous Action will be supported in Versions later than ASP. net mvc Framework 1.0. I believe that all of the above defects can be compensated at that time. However, this requires a lot of work, which can only be handed over to the ASP. net mvc team for implementation. In fact, you can now find the content related to asynchronous Action processing in the MvcFutures project of ASP. net mvc source code. It has added many extensions such as IAsyncController, AsyncController, IAsyncActionInvoker, and AsyncControllerActionInvoker. Although they all "inherit" existing classes, they are similar to my previous judgment. For example, AsyncControllerActionInvoker has almost completely re-implemented various functions in ActionInvoker-I have not carefully read the code, therefore, it is impossible to determine whether the design is good, just hope it can be like ASP. net mvc itself is as simple and elegant.
I plan to add Filter support for the EndXxx method of the current Code. I need to carefully read the ASP. NET MVC source code to find a solution. It is expected that ASP. net mvc will be a better alternative to supporting asynchronous actions.
- AsyncState parameter of ASP. NET
- ASP. net mvc executes asynchronous Action
- Overview ASP. net mvc Framework
- Use the UpdataModel method in ASP. NET MVC
- ASP. net mvc Action Method