您的位置:首页 > 编程语言 > ASP

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

2012-12-05 21:06 573 查看
紧接着上文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);

他才是真正实现转化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: