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

来源:互联网 发布:算法流程图怎么画 编辑:程序博客网 时间:2024/06/09 14:02

        上篇说到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

大脑短路中,明天继续。

0 0
原创粉丝点击