上篇说到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(); }
好吧,先找最重要的,找到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; }
接下来我们看一下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
大脑短路中,明天继续。