asp.net mvc源码分析-Action篇 Action的执行

接着上篇 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代码如下:

  其实这段代码是很好理解的就是用表达式树来生成一个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"};}
    }

返回结果:

posted on   dz45693  阅读(1894)  评论(0编辑  收藏  举报

编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构

导航

< 2012年11月 >
28 29 30 31 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 1
2 3 4 5 6 7 8
点击右上角即可分享
微信分享提示