[上一篇]中我们说到了对象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. java.lang.ClassNotFoundException: org.springframework.web.filter.CharacterEncodingFilter

    今天在用git merge 新代码后报了如下错误:java.lang.ClassNotFoundException: org.springframework.web.filter.CharacterE ...

  2. js流程控制题——如何实现一个LazyMan

    先说一下想要的效果: lazyMan('zz').eat('lunch').sleep('3').eat('dinner')输出: Hi!This is zz! Eat lunch~ //有3s间隔等 ...

  3. HTML5 十大新特性(五)——SVG绘图

    相对于canvas绘图,SVG是一种绘制矢量图的技术.全称叫做Scalable Vector Graphics,可缩放的矢量图,在2000年就已经存在,H5把它纳入了标准标签库,并进行了一些瘦身.需要 ...

  4. 使用JavaMail实现发送邮件功能

    package com.dunn.model; import java.util.Properties; import javax.mail.Address; import javax.mail.Me ...

  5. js控制 input框中输入数字时,累计求和

    $('.cc input').bind('input propertychange', function(){ var total = 0; $("input").each(fun ...

  6. C#中 Request, Request.params , Request.querystring , Request.Form 区别 与联系用法

    C#中 Request, Request.params , Request.querystring , Request.Form 区别 与联系用法? Request.params , Request ...

  7. 即时聊天IM之二 openfire 整合现有系统用户

    合肥程序员群:49313181.    合肥实名程序员群:128131462 (不愿透露姓名和信息者勿加入) Q  Q:408365330     E-Mail:egojit@qq.com  综述: ...

  8. Accessibility应用之focus篇

    最近项目中需要应用accessibility,大量使用了focus和blur,总结如下 一.设置焦点focus 如创建无障碍对话框:当一个对话框出现时,焦点应在对话框内,这样用户才可以使用键盘继续浏览 ...

  9. 安装VS 2013遇到的问题,及解决方案

    一.在启动调试时报错 Visual Studio 2013 虽然集成安装了 IIS Express 8.0,但是并未安装 WebMatrix ,第一个问题就是这个原因造成的. 解决方案: 1.下载最新 ...

  10. 恢复 root 本地无权限 Access denied for user 'root'@'localhost' (using password: NO)

    调试远程的时候,覆盖了本地的权限.导致  本地无法登陆系统表.  远程连接上mysql  执行以下命令恢复. 恢复root  本地管理权限  使用空密码 grant all on *.* to roo ...