[上一篇]中我们说到了对象AsyncControllerActionInvoker,在Controller的ExecuteCore方法中调用AsyncControllerActionInvoker对象的InvokeAction方法来执行动作方法.

public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
if (string.IsNullOrEmpty(actionName))
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);
ActionDescriptor action = this.FindAction(controllerContext, controllerDescriptor, actionName);
if (action == null)
return false;
FilterInfo filters = this.GetFilters(controllerContext, action);
try
{
AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, action);
if (authorizationContext.Result != null)
{
this.InvokeActionResult(controllerContext, authorizationContext.Result);
}
else
{
if (controllerContext.Controller.ValidateRequest)
ControllerActionInvoker.ValidateRequest(controllerContext);
IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, action);
ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, action, parameterValues);
this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, actionExecutedContext.Result);
}
}
catch (ThreadAbortException ex)
{
throw;
}
catch (Exception ex)
{
ExceptionContext exceptionContext = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, ex);
if (!exceptionContext.ExceptionHandled)
throw;
else
this.InvokeActionResult(controllerContext, exceptionContext.Result);
}
return true;
}

这个方法是在AsyncControllerActionInvoker的基类ControllerActionInvoker中实现的,而且做了很做工作,我们来逐步分解这个方法,首先,获取控制器的描述对象方法

protected virtual ControllerDescriptor GetControllerDescriptor(ControllerContext controllerContext)
{
Type controllerType = controllerContext.Controller.GetType();
return this.DescriptorCache.GetDescriptor(controllerType, (Func<ControllerDescriptor>) (() => (ControllerDescriptor) new ReflectedControllerDescriptor(controllerType)));
}

在这个方法中,获取Controller描述对象默认为ReflectedControllerDescriptor。然后再根据动作方法名称获取动作描述对象ActionDescriptor,

protected virtual ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
{
return controllerDescriptor.FindAction(controllerContext, actionName);
}

可以看到其实调用的是控制器描述对象的获取动作描述对象的方法,我们根据获取的默认控制器描述对象ReflectedControllerDescriptor,查看它的FindAction:

public override ActionDescriptor FindAction(ControllerContext controllerContext, string actionName)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
if (string.IsNullOrEmpty(actionName))
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
MethodInfo actionMethod = this._selector.FindActionMethod(controllerContext, actionName);
if (actionMethod == (MethodInfo) null)
return (ActionDescriptor) null;
else
return (ActionDescriptor) new ReflectedActionDescriptor(actionMethod, actionName, (ControllerDescriptor) this);
}

返回默认是封装了要调用的方法对象 MethodInfo的ReflectedActionDescriptor对象。

  下来一步是根据控制器上下文和动作描述对象获取到应用到动作和控制器上的所有筛选器,并从获取到的所有筛选器中得到授权过滤器,然后对每个授权过滤器调用OnAuthorization方法,判断返回的AuthorizationContext的Result如果不为空,就直接调用动作结果方法InvokeActionResult。如果为空,说明授权都通过了,然后获取动作方法的参数和根据模型绑定器绑定参数值,(这里会涉及到另外一个组件IModelBinder,我们会在后续详细谈论它,在这里我们就只需知道他会根据参数名称从请求的数据中绑定参数值)

protected virtual IDictionary<string, object> GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
Dictionary<string, object> dictionary = new Dictionary<string, object>((IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase);
foreach (ParameterDescriptor parameterDescriptor in actionDescriptor.GetParameters())
dictionary[parameterDescriptor.ParameterName] = this.GetParameterValue(controllerContext, parameterDescriptor);
return (IDictionary<string, object>) dictionary;
}
protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
{
Type parameterType = parameterDescriptor.ParameterType;
IModelBinder modelBinder = this.GetModelBinder(parameterDescriptor);
IValueProvider valueProvider = controllerContext.Controller.ValueProvider;
string str = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;
Predicate<string> propertyFilter = ControllerActionInvoker.GetPropertyFilter(parameterDescriptor);
ModelBindingContext bindingContext = new ModelBindingContext()
{
FallbackToEmptyPrefix = parameterDescriptor.BindingInfo.Prefix == null,
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType((Func<object>) null, parameterType),
ModelName = str,
ModelState = controllerContext.Controller.ViewData.ModelState,
PropertyFilter = propertyFilter,
ValueProvider = valueProvider
};
return modelBinder.BindModel(controllerContext, bindingContext) ?? parameterDescriptor.DefaultValue;
}

再下来根据控制器描述对象,动作描述对象和或取得的参数执行InvokeActionMethod方法:

protected virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
{
object actionReturnValue = actionDescriptor.Execute(controllerContext, parameters);
return this.CreateActionResult(controllerContext, actionDescriptor, actionReturnValue);
}

在这里我们发现方法执行的关键是在actionDescriptor.Execute(controllerContext, parameters),我们知道这个actionDescriptor是个ReflectedActionDescriptor对象,

public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
if (parameters == null)
throw new ArgumentNullException("parameters");
object[] parameters1 = Enumerable.ToArray<object>(Enumerable.Select<ParameterInfo, object>((IEnumerable<ParameterInfo>) this.MethodInfo.GetParameters(), (Func<ParameterInfo, object>) (parameterInfo => ActionDescriptor.ExtractParameterFromDictionary(parameterInfo, parameters, this.MethodInfo))));
return this.DispatcherCache.GetDispatcher(this.MethodInfo).Execute(controllerContext.Controller, parameters1);
}

最后一步,我们发现调用的是ActionMethodDispatcher对象(这个是个内部对象,它封装了我们要调用的方法对象methodInfo)的Execute方法

public object Execute(ControllerBase controller, object[] parameters)
{
return this._executor(controller, parameters);
}

,我们发现,它是把我们当前调用的controller对象和要调用的方法的参数作为参数进行调用的,而_executor是个委托对象,我们可以通过ActionMethodDispatcher的构造函数看到它的值

public ActionMethodDispatcher(MethodInfo methodInfo)
{
this._executor = ActionMethodDispatcher.GetExecutor(methodInfo);
this.MethodInfo = methodInfo;
}

来自于方法GetExecutor,继续

private static ActionMethodDispatcher.ActionExecutor GetExecutor(MethodInfo methodInfo)
{
ParameterExpression parameterExpression1 = Expression.Parameter(typeof (ControllerBase), "controller");
ParameterExpression parameterExpression2 = Expression.Parameter(typeof (object[]), "parameters");
List<Expression> list = new List<Expression>();
ParameterInfo[] parameters = methodInfo.GetParameters();
for (int index = 0; index < parameters.Length; ++index)
{
ParameterInfo parameterInfo = parameters[index];
UnaryExpression unaryExpression = Expression.Convert((Expression) Expression.ArrayIndex((Expression) parameterExpression2, (Expression) Expression.Constant((object) index)), parameterInfo.ParameterType);
list.Add((Expression) unaryExpression);
}
MethodCallExpression methodCallExpression = Expression.Call((Expression) (!methodInfo.IsStatic ? Expression.Convert((Expression) parameterExpression1, methodInfo.ReflectedType) : (UnaryExpression) null), methodInfo, (IEnumerable<Expression>) list);
if (methodCallExpression.Type == typeof (void))
return ActionMethodDispatcher.WrapVoidAction(Expression.Lambda<ActionMethodDispatcher.VoidActionExecutor>((Expression) methodCallExpression, new ParameterExpression[2]
{
parameterExpression1,
parameterExpression2
}).Compile());
else
return Expression.Lambda<ActionMethodDispatcher.ActionExecutor>((Expression) Expression.Convert((Expression) methodCallExpression, typeof (object)), new ParameterExpression[2]
{
parameterExpression1,
parameterExpression2
}).Compile();
}

 这个方法是把我们传进来的要调用的methodInfo对象,构建了一个表达式形式如:(ControllerBase,object[])=>ControllerBase.MethodInfo(object[]),我们发现他就是构造了_executor类型的委托的表达式,而它的类型为

private delegate object ActionExecutor(ControllerBase controller, object[] parameters);

它的调用则为ActionMethodDispatcher.Execute()方法,就是调用了当前controller对象中定义的方法,得到返回值

protected virtual ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)
{
if (actionReturnValue == null)
return (ActionResult) new EmptyResult();
ActionResult actionResult = actionReturnValue as ActionResult;
if (actionResult == null)
actionResult = (ActionResult) new ContentResult()
{
Content = Convert.ToString(actionReturnValue, (IFormatProvider) CultureInfo.InvariantCulture)
};
return actionResult;
}

得到执行结果对象ActionResult,把这个对象封装到ActionExecutedContext对象中返回,然后调用InvokeActionResultWithFilters方法,最终都会调用的方法就是InvokeActionResult方法,而这个方法中

protected virtual void InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
{
actionResult.ExecuteResult(controllerContext);
}

会涉及到另外一个对象ActionResult,这个对象会把最终的结果呈现给客户端!

MVC 请求处理流程(二)的更多相关文章

  1. ASP.Net请求处理机制初步探索之旅 - Part 5 ASP.Net MVC请求处理流程

    好听的歌 我一直觉得看一篇文章再听一首好听的歌,真是种享受.于是,我在这里嵌入一首好听的歌,当然你觉得不想听的话可以点击停止,歌曲 from 王菲 <梦中人>: --> 开篇:上一篇 ...

  2. ASP.Net MVC请求处理流程

    ASP.Net MVC请求处理流程 好听的歌 我一直觉得看一篇文章再听一首好听的歌,真是种享受.于是,我在这里嵌入一首好听的歌,当然你觉得不想听的话可以点击停止,歌曲 from 王菲 <梦中人& ...

  3. asp.net mvc 请求处理流程,记录一下。

    asp.net mvc 请求处理流程,记录一下.

  4. Spring MVC 请求处理流程概览

    SpringMVC工作流程 图一:请求流程概述 图二:请求在每个组件的处理 解释Spring工作流程 1.用户向服务器发送请求,请求被spring前端控制Servelt DispatcherServe ...

  5. Spring MVC请求处理流程

    从web.xml中 servlet的配置开始, 根据servlet拦截的url-parttern,来进行请求转发   Spring MVC工作流程图   图一   图二    Spring工作流程描述 ...

  6. Spring mvc请求处理流程详解(一)之视图解析

      本文链接:https://blog.csdn.net/lchpersonal521/article/details/53112728 前言 Spring mvc框架相信很多人都很熟悉了,关于这方面 ...

  7. MVC 请求处理流程(一)

    路由系统先获取路由数据,在实现了IHttpModule接口的UrlRoutingModule对象中通过注册HttpApplication的PostResolveRequestCache来解析路由数据并 ...

  8. ASP.NET的MVC请求处理流程

    1.用户打开浏览器,在地址栏输入某个网址的URL并回车,浏览器便开始像该URL指定的服务器发起HTTP请求 .2.服务器的网站服务系统(IIS)接收到该请求,先检查自己是否认识该类请求,如果认识就直接 ...

  9. 2017.3.31 spring mvc教程(二)核心流程及配置详解

    学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...

随机推荐

  1. Opentaps安装小记

    这周了解了个MES项目需求,于是乎找了些开源项目了解下,有php+mysql写的weberp,配置起来相当方便,下一版webERP_v4.13,往F:\Apache\htdocs\一放,启动F:\Ap ...

  2. ios回调函数的标准实现:protocol+delegate

    一.项目结构

  3. TypeError: coercing to Unicode: need string or buffer, ChatRoom found

    在用django框架中遇到一个错误,是模型编写中出的错误 TypeError: coercing to Unicode: need string or buffer, ChatRoom found 解 ...

  4. jQuery对象与dom对象的转换

    一直以来对于通过jQuery方式获取的对象使不能直接使用JavaScript的一些方法的,开始的时候不理解,现在此案知道,原来jQuery获得的对象并不和我们平时使用getElementById获得的 ...

  5. NFA引擎匹配原理

    1       为什么要了解引擎匹配原理 一个个音符杂乱无章的组合在一起,弹奏出的或许就是噪音,同样的音符经过作曲家的手,就可以谱出非常动听的乐曲,一个演奏者同样可以照着乐谱奏出动听的乐曲,但他/她或 ...

  6. MVC5+EF6 入门完整教程四

    上篇文章主要讲了如何配置EF, 我们回顾下主要过程: 创建Data Model à 创建Database Context à创建databaseInitializerà配置entityFramewor ...

  7. [IOS 开发] TableView、多个TableViewCell、自定义Cell、Cell上画画(故事板+代码方式)

    第一步: //UserTableViewCell.h这里定义第一种Cell #import <UIKit/UIKit.h> @interface UserTableViewCell : U ...

  8. Swift 04.Functions

    函数的基本构造 基本结构 func 函数名 (形参名:形参类型) ->返回值 {实现代码} 如果没有参数,那么也必须把参数的括号带上 如果有多个形参,那么必须以逗号 , 隔开 如果没有返回值,那 ...

  9. ionic单页面应用中微信分享的问题总结

    首先说一下 ionic 是单页面应用,也就是说整个项目就有一个index.html, 那么问题就就来了, 如果我们不同的页面要分享给大家的是不同的链接和图片,应该怎么去做呢? 这就是我们今天要总结的东 ...

  10. Game02 最新版本2.0.0

    Game02发布转站于此,欢迎大家下载.... 简介: Game02是由ImGenius开发的一款即时在线小游戏.玩法简单,易于上手,主要靠技术,不会出现不要脸的充值等内容. 操控方法:W和A左右移动 ...