zoukankan      html  css  js  c++  java
  • asp.net mvc源码分析AsyncController

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

    首先看一个demo吧:

     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);
             }

    网上对AsyncController也有些意见

    此外还要另外注意几点:

           1.对于异步请求,当发起另外一个线程去处理请求没有返回怎么办,比如抛出异常?框架默认的超时时间是45秒,在45秒到了之后框架会抛出一个System.TimeoutException以中止这个异步请求,我们可以通过[AsyncTimeOut((int duration)]来设置超时时间,还可以通过NoAsyncTimeout或者[AsyncTimeout(Timeout.Infinite)]来设置永不过期。

           2.可以使用AsyncManager.Finish方法来中止所有还未结束的异步操作,进而调用Completed action,如果被强制中止的异步操作还没有成功返回某些参数时,Completed将使用这些参数的默认值(如int为0,string为empty)。

           3.AsyncManager.Sync方法的作用

    我喜欢看看源代码,知道这一切都是为什么。我一次做AsyncController我的问题是它是这么调用回调函数的,参数又是如何获取的了。

    首先看看AsyncController 的定义:

      public abstract class AsyncController : Controller, IAsyncManagerContainer, IAsyncController 

        public interface IAsyncController : IController {
            IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state);
            void EndExecute(IAsyncResult asyncResult);

        }

       public interface IAsyncManagerContainer {
    AsyncManager AsyncManager { get;}
    }

    这里我们知道AsyncController实现了异步的效果,同时里面还有一个AsyncManager ,我们知道执行Action的一个关键类是ControllerActionInvoker类,在AsyncController应该创建一个和它差不多的类啊?实现这个功能的在这句代码:

      protected override IActionInvoker CreateActionInvoker() {
                return new AsyncControllerActionInvoker();
            }

     public class AsyncControllerActionInvoker : ControllerActionInvoker, IAsyncActionInvoker

    从AsyncControllerActionInvoker 的定义我们知道它实现了异步功能。它的结构和我们的ControllerActionInvoker相差不大,在它的GetControllerDescriptor方法中有这么一句:ControllerDescriptor controllerDescriptor = DescriptorCache.GetDescriptor(controllerType, () => newReflectedAsyncControllerDescriptor(controllerType));

    ReflectedAsyncControllerDescriptor和ReflectedControllerDescriptor类相差不大,只不过ReflectedControllerDescriptor里面用到了ActionMethodSelector查找参数,而ReflectedAsyncControllerDescriptor用的是AsyncActionMethodSelector查找参数

    在AsyncActionMethodSelector的GetActionDescriptorDelegate方法中有点特殊:

            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);
            }

    从这里我们知道我们的方法名应该命名位xxxAsync()->xxxCompleted()这个格式,系统会自己调用对应的回调方法也只有以这种命名了的方法才是真正实现了异步的,不然又返回一个普通的ReflectedActionDescriptor,在这里我们可以猜测ReflectedAsyncActionDescriptor应该是实现了异步模式的

    public class ReflectedAsyncActionDescriptor : AsyncActionDescriptor

    在ReflectedAsyncActionDescriptor的BeginExecute方法中主要内容如下:

     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
                                                       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);

    这里我们就可以确定程序在调用了XxxAsync之后会自动调用XxxCompleted方法,XxxCompleted所需参数的值会从AsyncManager。Parameters中获取。这里面的具体实现还是很复杂了,我们就滤过了吧。

  • 相关阅读:
    我所了解的meta
    移动端遇到的问题
    反编译工具
    Nginx安装及配置免费HTTPS证书
    Python中通过lambda抛异常的奇技淫巧
    理解PEP333-WSGI
    Doker学习笔记之一:安装
    《程序员修炼之道》备忘清单
    日常开发工具列表
    NLP入门资料
  • 原文地址:https://www.cnblogs.com/majiang/p/2768202.html
Copyright © 2011-2022 走看看