带你读开源—ASP.NET_MVC(三)

        上篇说到ControllerActionInvoker的InvokeAction方法,今天继续。

        谈点题外话,MVC中大量使用接口和IOC,即控制反转(或依赖注入),这个我们留个专题讨论。

        在ControllerActionInvoker的InvokeAction方法实现中,主要用到了Filter,即过滤器。Filter我们一直没有提及,因为不想让它分散大家的注意力,因为MVC太庞杂了,以后会专门开辟章节谈Filter。

        ControllerActionInvoker的InvokeAction方法的大意是:首先检查用户是否应用了过滤器,是的话就执行过滤器,并检测其Result属性,不为空的话,就使HTTP请求“短路”,即直接返回Filter指定的操作,不再执行Action。反之,则继续执行Action。

        这里用到了AuthenticationContext和AuthorizationContext,尼玛这俩货是不是长得很像?我看了半天才看出他俩不是一个。反正它们是关于认证和授权过滤的,先不管他们。找到InvokeActionMethodWithFilters方法(代码段1),这个方法乍一看比较难理解,一大堆委托和Lamda表达式,看得人头大。

        protected virtual ActionExecutedContextInvokeActionMethodWithFilters(ControllerContext controllerContext,IList<IActionFilter> filters, ActionDescriptor actionDescriptor,IDictionary<string, object> parameters)
        {
            ActionExecutingContext preContext =new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
            Func<ActionExecutedContext>continuation = () =>
                                                      new ActionExecutedContext(controllerContext, actionDescriptor, false /*canceled */, null /* exception */)
                                                      {
                                                          Result = InvokeActionMethod(controllerContext, actionDescriptor,parameters)
                                                      };
 
            // need to reverse the filter listbecause the continuations are built up backward
            Func<ActionExecutedContext>thunk = filters.Reverse().Aggregate(continuation,
                                                                           (next, filter) => () => InvokeActionMethodFilter(filter,preContext, next));
            return thunk();
        }

代码段 1

        好吧,先找最重要的,找到InvokeActionMethod方法(代码段2),看!是不是有点豁然开朗的赶脚?代码段2中的actionDescriptor.Execute方法便是调用我们定义的Controller/Action方法的地方。

        protected virtual ActionResultInvokeActionMethod(ControllerContext controllerContext, ActionDescriptoractionDescriptor, IDictionary<string, object> parameters)
        {
            object returnValue =actionDescriptor.Execute(controllerContext, parameters);
            ActionResult result =CreateActionResult(controllerContext, actionDescriptor, returnValue);
            return result;
        }

代码段 2

        接下来我们看一下ActionDescriptor,这个类有个抽象方法Execute,它有个子类ReflectedActionDescriptor,从名字可以看出这个类是使用反射来干什么事情的。ReflectedActionDescriptor类的Execute方法见代码段3。

       

 public override objectExecute(ControllerContext controllerContext, IDictionary<string, object>parameters)
        {
            if (controllerContext == null)
            {
                throw newArgumentNullException("controllerContext");
            }
            if (parameters == null)
            {
                throw newArgumentNullException("parameters");
            }
 
            // Performance sensitive so avoidLinq or delegates.
            ParameterInfo[] parameterInfos =MethodInfo.GetParameters();
            object[] parametersArray = newobject[parameterInfos.Length];
            for (int i = 0; i <parameterInfos.Length; i++)
            {
                ParameterInfo parameterInfo =parameterInfos[i];
                object parameter =ExtractParameterFromDictionary(parameterInfo, parameters, MethodInfo);
                parametersArray[i] = parameter;
            }
 
            ActionMethodDispatcher dispatcher =DispatcherCache.GetDispatcher(MethodInfo);
            object actionReturnValue =dispatcher.Execute(controllerContext.Controller, parametersArray);
            return actionReturnValue;
        }

代码段 3

        继续跟踪到dispatcher.Execute方法(代码段4)。

        public object Execute(ControllerBasecontroller, object[] parameters)
        {
            return _executor(controller,parameters);
        }


代码段 4

        嗯,_executor是个什么东东?我们找到其定义(代码段5),原来它是一个ActionExecutor对象,那么这个对象又是在哪里实例化的呢?在代码段5中找到这句【_executor = GetExecutor(methodInfo)】。

        private ActionExecutor _executor;
 
        publicActionMethodDispatcher(MethodInfo methodInfo)
        {
            _executor =GetExecutor(methodInfo);
            MethodInfo = methodInfo;
        }


代码段 5

        继续跟踪GetExecutor方法,找到其定义。该方法的定义有点晦涩,一堆Expression、Lamda等东东,我们找到【MethodCallExpression methodCall = methodCall =Expression.Call(instanceCast, methodInfo, parameters)】,这句的意思大概就是调用methodInfo代表的Action方法吧。

好了,到此为止,Controller/Action的调用就完成了。

        在这里插一点,就是我们的Action不一定非要返回一个ActionResult,也可以定义为void,例如代码段6,直接在Action中给浏览器发回HTTP响应。

publicvoid Index()
{
HttpContex.Current.Response.Write(“我就不返回ActionResult!”);
}


代码段 6

        MVC是怎么根据Action有没有返回值,进行不同的处理呢?见代码段7,MVC根据methodCall.Type是否为void,进行不同的处理,明白了吧?对于void类型,直接调用Action方法,不再使用视图引擎。

//methodCall is "((TController) controller) method((T0) parameters[0], (T1)parameters[1], ...)"
            // Create function
            if (methodCall.Type ==typeof(void))
            {
                Expression<VoidActionExecutor>lambda = Expression.Lambda<VoidActionExecutor>(methodCall,controllerParameter, parametersParameter);
                VoidActionExecutor voidExecutor= lambda.Compile();
                returnWrapVoidAction(voidExecutor);
            }
            else
            {
                // must coerce methodCall tomatch ActionExecutor signature
                UnaryExpression castMethodCall= Expression.Convert(methodCall, typeof(object));
               Expression<ActionExecutor> lambda =Expression.Lambda<ActionExecutor>(castMethodCall, controllerParameter,parametersParameter);
                return lambda.Compile();
            }


代码段 7

        再下面就是ActionResult的执行了。

        这里跨度有点大,我们再次转到ControllerActionInvoker的InvokeAction方法。继InvokeActionMethodWithFilters方法之后,找到InvokeActionResultWithFilters方法,再顺藤摸瓜,找到InvokeActionResultFilterRecursive方法。这个方法有意思,他的名字里面有个单词Recursive,意思是“递归”,它递归处理Filter列表,如果递归完成则调用InvokeActionResult方法,这个方法执行ActionResult的ExecuteResult方法(代码段8),像浏览器回送HTTP响应。

        protected virtual voidInvokeActionResult(ControllerContext controllerContext, ActionResultactionResult)
        {
           actionResult.ExecuteResult(controllerContext);
        }

代码段 8

大脑短路中,明天继续。

你可能感兴趣的:(带你读开源—ASP.NET_MVC(三))