asp.net mvc源码分析-AsyncController

[来源] 达内    [编辑] 达内   [时间]2012-11-13

我们前面的讲的都是基于同步的Controller来实现,现在我们来看看基于异步的AsyncController又是如何实现的

我们前面的讲的都是基于同步的Controller来实现,现在我们来看看基于异步的AsyncController又是如何实现的。

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">首先看一个demo吧:

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); "> public void IndexAsync ()
          {
              //实现异步action加计数1
              FileStream fileStream = new FileStream(@"D:\channel.txt", FileMode.Open);
             byte[] byteArray = new byte[fileStream.Length];
             fileStream.BeginRead(byteArray, 0, (int)fileStream.Length, (IAsyncResult result) =>
              {
                 string content = Encoding.Default.GetString(byteArray);
                 //参数要放在这个字典里面实现向Completed action传递
                 AsyncManager.Parameters["content"] = content;
                 //异步action回调结束
                 fileStream.Close();
            }, null);
         }
        //这个action以Completed为后缀异步action结束后调用的函数,返回值为ActionResult
       public ActionResult IndexCompleted(string content)
         {
             return Content(content);
         }

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">网上对AsyncController也有些意见

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">此外还要另外注意几点:

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">        1.对于异步请求,当发起另外一个线程去处理请求没有返回怎么办,比如抛出异 ?框架默认的超时时间是45秒,在45秒到了之后框架会抛出一个System.TimeoutException以中止这个异步请求,我们可以通过[AsyncTimeOut((int duration)]来设置超时时间,还可以通过NoAsyncTimeout或者[AsyncTimeout(Timeout.Infinite)]来设置永不过期。

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">        2.可以使用AsyncManager.Finish方法来中止所有还未结束的异步操作,进而调用Completed action,如果被强制中止的异步操作还没有成功返回某些参数时,Completed将使用这些参数的默认值(如int为0,string为empty)。

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">       3.AsyncManager.Sync方法的作用

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); "> 我喜欢看看源代码,知道这一切都是为什么。我一次做AsyncController我的问题是它是这么调用回调函数的,参数又是如何获取的了。

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">首先看看AsyncController 的定义:

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">  public abstract class  AsyncController : Controller, IAsyncManagerContainer, IAsyncController 

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">    public interface IAsyncController : IController {
        IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state);
        void EndExecute(IAsyncResult asyncResult);

    }

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">   public interface IAsyncManagerContainer {
AsyncManager AsyncManager { get;}
}

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">从 这里我们知道AsyncController实现了异步的效果,同时里面还有一个AsyncManager  ,我们知道执行Action的一个关键类是ControllerActionInvoker类,在AsyncController应该创建一个和它差不多的类啊?实现这个功能的在这句代码:

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">  protected override  IActionInvoker CreateActionInvoker() {
            return new AsyncControllerActionInvoker();
        }

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); "> public class  AsyncControllerActionInvoker : ControllerActionInvoker, IAsyncActionInvoker

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); "> 从AsyncControllerActionInvoker 的定义我们知道它实现了异步功能。它的结构和我们的ControllerActionInvoker相差不大,在它的GetControllerDescriptor方法中有这么一句:ControllerDescriptor controllerDescriptor = DescriptorCache.GetDescriptor(controllerType, () =>  newReflectedAsyncControllerDescriptor(controllerType));

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">而 ReflectedAsyncControllerDescriptor和ReflectedControllerDescriptor类相差不大,只不过ReflectedControllerDescriptor里面用到了ActionMethodSelector查找参数,而ReflectedAsyncControllerDescriptor用的是AsyncActionMethodSelector查找参数

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">在AsyncActionMethodSelector的GetActionDescriptorDelegate方法中有点特殊:

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">         private ActionDescriptorCreator GetActionDescriptorDelegate(MethodInfo entryMethod) {
            // Is this the FooAsync() / FooCompleted() pattern?
            if (IsAsyncSuffixedMethod(entryMethod)) {
                 string completionMethodName = entryMethod.Name.Substring(0, entryMethod.Name.Length - "Async".Length) + "Completed";
                MethodInfo completionMethod = GetMethodByName(completionMethodName);
                if (completionMethod != null) {
                    return (actionName, controllerDescriptor) => new ReflectedAsyncActionDescriptor (entryMethod, completionMethod, actionName, controllerDescriptor);
                }
                else {
                    throw Error.AsyncActionMethodSelector_CouldNotFindMethod(completionMethodName, ControllerType);
                }
            }

            // Fallback to synchronous method
            return (actionName, controllerDescriptor) => new ReflectedActionDescriptor(entryMethod, actionName, controllerDescriptor) ;
        }
  private static bool IsAsyncSuffixedMethod(MethodInfo methodInfo) {
            return methodInfo.Name.EndsWith("Async", StringComparison.OrdinalIgnoreCase);
        }

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">从这里我们知道 我们的方法名应该命名位xxxAsync()->xxxCompleted()这个格式,系统会自己调用对应的回调方法 也只有以这种命名了的方法才是真正实现了异步的,不然又返回一个普通的ReflectedActionDescriptor,在这里我们可以猜测ReflectedAsyncActionDescriptor应该是实现了异步模式的

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">public class  ReflectedAsyncActionDescriptor : AsyncActionDescriptor

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">在ReflectedAsyncActionDescriptor的BeginExecute方法中主要内容如下:

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); "> AsyncManager asyncManager = GetAsyncManager(controllerContext.Controller);
            BeginInvokeDelegate beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState) {
                // call the XxxAsync() method
                ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(AsyncMethodInfo);
                dispatcher.Execute(controllerContext.Controller, parametersArray); 
// ignore return value from this method
                return asyncResult;
            };
            EndInvokeDelegate<object> endDelegate = delegate(IAsyncResult asyncResult) {
                // call the XxxCompleted() method
                ParameterInfo[] completionParametersInfos = CompletedMethodInfo.GetParameters();
                var rawCompletionParameterValues = from parameterInfo in completionParametersInfos
& nbsp;                                                  select ExtractParameterOrDefaultFromDictionary(parameterInfo,asyncManager.Parameters);
                object[] completionParametersArray = rawCompletionParameterValues.ToArray();
                 ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(CompletedMethodInfo);
                object actionReturnValue = dispatcher.Execute(controllerContext.Controller, completionParametersArray);

                return actionReturnValue;
            };
            return AsyncResultWrapper.Begin(callback, state, beginDelegate, endDelegate, _executeTag,  asyncManager.Timeout);

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(51, 51, 51); font-family: verdana, 宋体, Arial; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: -webkit-auto; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); ">从这里 我们就可以确定程序在调用了XxxAsync之后会自动调用XxxCompleted方法,XxxCompleted所需参数的值会从AsyncManager。Parameters中获取。这里面的具体实现还是很复杂了,我们就滤过了吧。

资源下载