接着上篇 asp.net mvc源码分析-Action篇 DefaultModelBinder 我们已经获取的了Action的参数,有前面的内容我们知道Action的调用时在ControllerActionInvoker类的InvokeActionMethod方法。

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

我们现在知道actionDescriptor是ReflectedActionDescriptor类的一个实例,

ReflectedActionDescriptor的Execute方法的实现大致如下

public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters) {
            ParameterInfo[] parameterInfos = MethodInfo.GetParameters();
           var rawParameterValues = from parameterInfo in parameterInfos
                                     select ExtractParameterFromDictionary(parameterInfo, parameters, MethodInfo);
            object[] parametersArray = rawParameterValues.ToArray();
            ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(MethodInfo);
            object actionReturnValue = dispatcher.Execute(controllerContext.Controller, parametersArray);
            return actionReturnValue;
        }

ParameterInfo[] parameterInfos = MethodInfo.GetParameters();这句没什么说的就是获取Action的参数集合,大家应该知道方法参数中的parameters是什么东西吧,一个以Action参数名为key,其值为value的一个字典结合。

var rawParameterValues = from parameterInfo in parameterInfos
                                     select ExtractParameterFromDictionary(parameterInfo, parameters, MethodInfo);
            object[] parametersArray = rawParameterValues.ToArray();

这两句其实就是把parameters中参数value 按照Action中参数顺序组成一个数组。ExtractParameterFromDictionary方法就是检查parameters中的数据有效性。主要检查parameters是否包含parameterInfo.Name,没有抛异常,有则检查是否为null,为null是就检查 该参数是否允许为null,不允许则抛异常,不为null则检查值是否是参数类型的一个实例。

ActionMethodDispatcherCache实现如下:

internal sealed class ActionMethodDispatcherCache : ReaderWriterCache<MethodInfo,ActionMethodDispatcher> {
        public ActionMethodDispatcherCache() {}
        public ActionMethodDispatcher GetDispatcher(MethodInfo methodInfo) {
            return FetchOrCreateItem(methodInfo, () => new ActionMethodDispatcher(methodInfo));
        }
    }

这里 的FetchOrCreateItem我们就不说,在ActionMethodDispatcherCache类是曾经说过。这里的GetDispatcher其实是返回的ActionMethodDispatcher类的一个实例。

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

其中 GetExecutor代码如下:

 private static ActionExecutor GetExecutor(MethodInfo methodInfo) {// Parameters to executorParameterExpression controllerParameter = Expression.Parameter(typeof(ControllerBase), "controller");ParameterExpression parametersParameter = Expression.Parameter(typeof(object[]), "parameters");// Build parameter listList<Expression> parameters = new List<Expression>();ParameterInfo[] paramInfos = methodInfo.GetParameters();for (int i = 0; i < paramInfos.Length; i++) {ParameterInfo paramInfo = paramInfos[i];BinaryExpression valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));UnaryExpression valueCast = Expression.Convert(valueObj, paramInfo.ParameterType);// valueCast is "(Ti) parameters[i]"parameters.Add(valueCast);}// Call methodUnaryExpression instanceCast = (!methodInfo.IsStatic) ? Expression.Convert(controllerParameter, methodInfo.ReflectedType) : null;MethodCallExpression methodCall = methodCall = Expression.Call(instanceCast, methodInfo, parameters);// methodCall is "((TController) controller) method((T0) parameters[0], (T1) parameters[1], ...)"// Create functionif (methodCall.Type == typeof(void)) {Expression<VoidActionExecutor> lambda = Expression.Lambda<VoidActionExecutor>(methodCall, controllerParameter, parametersParameter);VoidActionExecutor voidExecutor = lambda.Compile();return WrapVoidAction(voidExecutor);}else {// must coerce methodCall to match ActionExecutor signatureUnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));Expression<ActionExecutor> lambda = Expression.Lambda<ActionExecutor>(castMethodCall, controllerParameter, parametersParameter);return lambda.Compile();}}

  其实这段代码是很好理解的,就是用表达式树来生成一个Action方法的调用。这段代码最后返回的是一个ActionExecutor的委托,在这个GetExecutor方法中有一句很耗时的是
lambda.Compile(),大家想过这里为什么要用表达式树而不直接调用MethodInfo的Invoke方法吗?,调用Invoke方其实也很慢,最主要是调用过程是没法缓存的;而用表达式虽然编译成委托时要慢点,但是这里有一个ActionMethodDispatcherCache来保证每个Action调用所需的委托实例只需编译一次,多次调用同一Action表达式就比Invoke方法性能高多了。看见微软在mvc3中缓存做的已经很好了。

object actionReturnValue = dispatcher.Execute(controllerContext.Controller, parametersArray);这句就是调用_executor委托,也就是真正执行Action方法,actionReturnValue 就是Action的返回值,默认是一个ActionResult。

现在 再来看看  ActionResult result = CreateActionResult(controllerContext, actionDescriptor, returnValue);这个方法吧:

protected virtual ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue) {
            if (actionReturnValue == null) {
                return new EmptyResult();
            }

ActionResult actionResult = (actionReturnValue as ActionResult) ??
                new ContentResult { Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture) };
            return actionResult;
        }

ActionResult actionResult = (actionReturnValue as ActionResult) ??new ContentResult { Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture) };就是 检查Action返回的是否是一个ActionResult,正常境况下都是的。如果返回的不是则构造一个ContentResult 返回,我在想如果Action返回的不是ActionResult,我们throw是不是更好了。

如 我们的Action如下

public class HomeController : Controller
    {
        public object Index(){return new  { Name="majiang"};}
    }

返回结果:

转载于:https://www.cnblogs.com/majiang/archive/2012/11/10/2764571.html

asp.net mvc源码分析-Action篇 Action的执行相关推荐

  1. asp.net mvc源码分析-Controllerl篇 ControllerDescriptor

    在上篇asp.net mvc源码分析-Controllerl篇 TempData数据存储 我们讲到了ActionInvoker.InvokeAction(ControllerContext, acti ...

  2. asp.net mvc源码分析-Action篇 DefaultModelBinder

    接着上篇 asp.net mvc源码分析-Controller篇 ValueProvider 现在我们来看看ModelBindingContext这个对象. ModelBindingContext b ...

  3. asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证

    asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证 原文:asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型 ...

  4. ASP.NET MVC源码分析系列

    Controller下的JsonResult的ExecuteResult方法 public override void ExecuteResult(ControllerContext context) ...

  5. Spring 源码分析衍生篇十 :Last-Modified 缓存机制

    文章目录 一.前言 二.Last-Modify 三.实现方案 1. 实现 org.springframework.web.servlet.mvc.LastModified接口 1.1. 简单演示 1. ...

  6. Lua源码分析 - 虚拟机篇 - 语义解析之Opcode执行(18)

    目录 一.虚拟机篇 - 指令执行状态机luaV_execute 二.虚拟机篇 - 状态机的具体实现原理 一.虚拟机篇 - 指令执行状态机luaV_execute 在<Lua源码分析 - 主流程篇 ...

  7. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

  8. 【OkHttp】OkHttp 源码分析 ( 同步 / 异步 Request 请求执行原理分析 )

    OkHttp 系列文章目录 [OkHttp]OkHttp 简介 ( OkHttp 框架特性 | Http 版本简介 ) [OkHttp]Android 项目导入 OkHttp ( 配置依赖 | 配置 ...

  9. Spring MVC源码分析(一) 说明

    为什么会有这一个系列的文章 现在正值大学的第一个暑假,这个暑假我准备开始进入框架的学习,首先我选择的是Spring MVC框架,这是自己学的第一个框架,我在学习的过程中不断告诉自己,这一次不是单纯的学 ...

最新文章

  1. 三维重建中的立体匹配详解
  2. UTF-8 BOM(EF BB BF)
  3. uniapp中使用picker_uniapp 使用个推推送系统消息
  4. ubuntu18.10的header文件搜索路径
  5. 《现代操作系统》读书笔记之——进程调度(二)
  6. 时钟同步及其应用(接上一篇)
  7. API的非向后兼容性无论如何通常代表着一种比较差的设计
  8. 不同维度的矩阵相乘的时间复杂度
  9. Javascript UserAgent 获取平台及浏览器信息
  10. Hbase实用技巧:全量+增量数据的迁移方法
  11. 交换机设备登录账号权限1_计算机网络管理员考试试题和答案
  12. tomcat开启远程调试
  13. 【转】全国最佳医院排名
  14. 人脸识别接口_智慧小区人脸识别门禁系统室外人脸识别门禁终端厂家
  15. 猎头是怎么找到合适候选人的?
  16. 计算3个地理坐标点之间的夹角
  17. 如何修改 Kubernetes 节点 IP 地址?
  18. NVIDIA系列显卡与AMD系列显卡性能对比,以及购买显卡的时候应该看哪些性能指标,NVIDIA显卡与AMD显卡的区别
  19. 电商策略2----超卖、少卖
  20. 熟练运用计算机软件英语,计算机软件英语论文

热门文章

  1. 性格倔强的女人,在感情中很难幸福
  2. 2021年已经过去了4天,创业者、负债累累而希望通过再创业实现东山再起者,你们准备的怎么样了?
  3. 为什么大家都会往大城市跑
  4. go 模板(template)的常用基本语法
  5. ubuntu卸载fcitx后引发的问题修复
  6. 一个动态增长的栈实现
  7. Mybatis_day1
  8. azure云数据库_Azure SQL数据库上的透明数据加密(TDE)
  9. Linux下安装Go环境
  10. python错误和调试