zoukankan      html  css  js  c++  java
  • 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的主要实现如下:

       private sealed class ActionExecutor
            {
                private readonly Func<object, object[], Task<object>> _executor;
    		 public ActionExecutor(MethodInfo methodInfo)
                {
                    Contract.Assert(methodInfo != null);
                    _executor = GetExecutor(methodInfo);
                }
    
                public Task<object> Execute(object instance, object[] arguments)
                {
                    return _executor(instance, arguments);
                }
    			  private static Func<object, object[], Task<object>> GetExecutor(MethodInfo methodInfo)
                {
                    // Parameters to executor
                    ParameterExpression instanceParameter = Expression.Parameter(typeof(object), "instance");
                    ParameterExpression parametersParameter = Expression.Parameter(typeof(object[]), "parameters");
    
                    // Build parameter list
                    List<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 method
                    UnaryExpression instanceCast = (!methodInfo.IsStatic) ? Expression.Convert(instanceParameter, methodInfo.ReflectedType) : null;
                    MethodCallExpression methodCall = methodCall = Expression.Call(instanceCast, methodInfo, parameters);
    
                    // methodCall is "((MethodInstanceType) instance).method((T0) parameters[0], (T1) parameters[1], ...)"
                    // Create function
                    if (methodCall.Type == typeof(void))
                    {
                        // for: public void Action()
                        Expression<Action<object, object[]>> lambda = Expression.Lambda<Action<object, object[]>>(methodCall, instanceParameter, parametersParameter);
                        Action<object, object[]> voidExecutor = lambda.Compile();
                        return (instance, methodParameters) =>
                        {
                            voidExecutor(instance, methodParameters);
                            return TaskHelpers.NullResult();
                        };
                    }
                    else
                    {
                        // must coerce methodCall to match Func<object, object[], object> signature
                        UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));
                        Expression<Func<object, object[], object>> lambda = Expression.Lambda<Func<object, object[], object>>(castMethodCall, instanceParameter, parametersParameter);
                        Func<object, object[], object> compiled = lambda.Compile();
                        if (methodCall.Type == typeof(Task))
                        {
                            // for: public Task Action()
                            return (instance, methodParameters) =>
                            {
                                Task r = (Task)compiled(instance, methodParameters);
                                ThrowIfWrappedTaskInstance(methodInfo, r.GetType());
                                return r.CastToObject();
                            };
                        }
                        else if (typeof(Task).IsAssignableFrom(methodCall.Type))
                        {
                            // for: public Task<T> Action()
                            // constructs: return (Task<object>)Convert<T>(((Task<T>)instance).method((T0) param[0], ...))
                            Type taskValueType = TypeHelper.GetTaskInnerTypeOrNull(methodCall.Type);
                            var compiledConversion = CompileGenericTaskConversionDelegate(taskValueType);
    
                            return (instance, methodParameters) =>
                            {
                                object callResult = compiled(instance, methodParameters);
                                Task<object> convertedResult = compiledConversion(callResult);
                                return convertedResult;
                            };
                        }
                        else
                        {
                            // for: public T Action()
                            return (instance, methodParameters) =>
                            {
                                var result = compiled(instance, methodParameters);
                                // Throw when the result of a method is Task. Asynchronous methods need to declare that they
                                // return a Task.
                                Task resultAsTask = result as Task;
                                if (resultAsTask != null)
                                {
                                    throw Error.InvalidOperation(SRResources.ActionExecutor_UnexpectedTaskInstance,
                                        methodInfo.Name, methodInfo.DeclaringType.Name);
                                }
                                return TaskHelpers.FromResult(result);
                            };
                        }
                    }
                }
    
    
    		}
    

     说白了就是用表达式树创建达表示调用我们的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);

    他才是真正实现转化。

  • 相关阅读:
    Python 实践
    Keras实践
    NLP S实践
    Spark java 实践
    Seaborn数据探索可视化
    Linux实践
    Redis
    ML算法选型
    Elasticsearch issue
    牛客练习赛37
  • 原文地址:https://www.cnblogs.com/majiang/p/2803962.html
Copyright © 2011-2022 走看看