Asp.net web Api源码分析-Action的执行

紧接着上文Asp.net web Api源码分析-HttpParameterBinding 我们已经把Action调用的参数准备好了,现在就该开始调用Action了,这里的 InvokeActionWithActionFilters(ApiController的ExecuteAsync方法)主要就是负责调用 ActionFilters和Action的,这里的调用模式和mvc中的调用方式一致。这里filiter的调用就不多说,我们来看看Action的调 用

controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken);

在DefaultServices中有如下代码 SetSingle<IHttpActionInvoker>(new ApiControllerActionInvoker());所以我们知道实际调用Action是在 ApiControllerActionInvoker的InvokeActionAsync方法。ApiControllerActionInvoker的InvokeActionAsync方法主要就一句

  return actionDescriptor.ExecuteAsync(controllerContext, actionContext.ActionArguments, cancellationToken)
                                       .Then(value => actionDescriptor.ResultConverter.Convert(controllerContext, value), cancellationToken);

这里的actionContext.ActionArguments是一个字典数据,key是参数名称,value参数值。

我们知道actionDescriptor这里是一个ReflectedHttpActionDescriptor实例,其ExecuteAsync方法主要代码实现如下:


  public override Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken)
        {
            return TaskHelpers.RunSynchronously(() =>
            {
                object[] argumentValues = PrepareParameters(arguments, controllerContext);
                return _actionExecutor.Value.Execute(controllerContext.Controller, argumentValues);
            }, cancellationToken);
        }

其中PrepareParameters方法主要是取出Action方法所需参数的值,并且还要做一些检查,PrepareParameters实现如下:

 private object[] PrepareParameters(IDictionary<string, object> parameters, HttpControllerContext controllerContext)
        {
            // This is on a hotpath, so a quick check to avoid the allocation if we have no parameters.
            if (_parameters.Value.Count == 0)
            {
                return _empty;
            }

            ParameterInfo[] parameterInfos = MethodInfo.GetParameters();
            int parameterCount = parameterInfos.Length;
            object[] parameterValues = new object[parameterCount];
            for (int parameterIndex = 0; parameterIndex < parameterCount; parameterIndex++)
            {
                parameterValues[parameterIndex] = ExtractParameterFromDictionary(parameterInfos[parameterIndex], parameters, controllerContext);
            }

            return parameterValues;
        }
其中ExtractParameterFromDictionary是真正取值的实现,直接调用 parameters.TryGetValue(parameterInfo.Name, out value)来取值,如果参数不存在抛出异常,如果值为null,而参数类型又不允许为null抛出异常,如果值不为null,值与参数类型不匹配抛出异 常,mvc中也有类似的检查。
这里的_actionExecutor.Value是个什么东东了,实际上是一个ActionExecutor实例,ActionExecutor的主要实现如下:

 说白了就是用表达式树创建达表示调用我们的Action。到这里我们的Action就真正的执行了返回一个object,
现在我们回到ApiControllerActionInvoker的InvokeActionAsync方法中 来, actionDescriptor.ResultConverter.Convert(controllerContext, value)把我们Action返回值转化为一个

HttpResponseMessage实例。

首先我们来看看HttpActionDescriptor的ResultConverter是如果定义的:

  public virtual IActionResultConverter ResultConverter
        {
            get
            {
                if (_converter == null)
                {
                    _converter = GetResultConverter(ReturnType);
                }
                return _converter;
            }
        }

这里ReturnType是我们Action的返回值类型。

 internal static IActionResultConverter GetResultConverter(Type type)
        {
            if (type != null && type.IsGenericParameter)
            {
                // This can happen if somebody declares an action method as:
                // public T Get<T>() { }
                throw Error.InvalidOperation(SRResources.HttpActionDescriptor_NoConverterForGenericParamterTypeExists, type);
            }

            if (type == null)
            {
                return _voidResultConverter;
            }
            else if (typeof(HttpResponseMessage).IsAssignableFrom(type))
            {
                return _responseMessageResultConverter;

            }
            else
            {
                Type valueConverterType = typeof(ValueResultConverter<>).MakeGenericType(type);
                return TypeActivator.Create<IActionResultConverter>(valueConverterType).Invoke();

            }
        }

一般情况下我们action的返回值都不是HttpResponseMessage类型,所以这里默认还回一个ValueResultConverter<T>实例,其中T就是我们Action的返回类型。这里就调用ValueResultConverter<T>的Convert方法把我们的Action返回值转化为HttpResponseMessage实例,在Convert中有一句

  return controllerContext.Request.CreateResponse<T>(HttpStatusCode.OK, value, controllerContext.Configuration);

他才是真正实现转化。

posted on   dz45693  阅读(3783)  评论(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年12月 >
25 26 27 28 29 30 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 31 1 2 3 4 5
点击右上角即可分享
微信分享提示