asp.net mvc源码分析-Action篇 Action的执行
2012-11-10 23:06
681 查看
接着上篇 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 executor
ParameterExpression controllerParameter = Expression.Parameter(typeof(ControllerBase), "controller");
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(controllerParameter, methodInfo.ReflectedType) : null;
MethodCallExpression methodCall = methodCall = Expression.Call(instanceCast, methodInfo, parameters);
// methodCall is "((TController) controller) method((T0) parameters[0], (T1) parameters[1], ...)"
// Create function
if (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 signature
UnaryExpression 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"};}
}
返回结果:
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 executor
ParameterExpression controllerParameter = Expression.Parameter(typeof(ControllerBase), "controller");
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(controllerParameter, methodInfo.ReflectedType) : null;
MethodCallExpression methodCall = methodCall = Expression.Call(instanceCast, methodInfo, parameters);
// methodCall is "((TController) controller) method((T0) parameters[0], (T1) parameters[1], ...)"
// Create function
if (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 signature
UnaryExpression 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"};}
}
返回结果:
相关文章推荐
- asp.net mvc源码分析-Action篇 Action的执行
- asp.net mvc源码分析-Action篇 DefaultModelBinder
- Asp.net web Api源码分析-Action的执行
- asp.net mvc源码分析-Action篇 ParameterDescriptor
- asp.net mvc源码分析-Action篇 DefaultModelBinder
- Asp.net web Api源码分析-Action的执行
- asp.net mvc源码分析-Action篇 ParameterDescriptor
- asp.net mvc源码分析-Action篇 IModelBinder
- asp.net mvc源码分析-Action篇 Filter
- asp.net mvc源码分析-Action篇 IModelBinder
- asp.net mvc源码分析-Action篇 IModelBinder
- asp.net mvc源码分析-Action篇 Filter
- asp.net mvc 之旅 —— 第六站 ActionFilter的应用及源码分析
- ASP.NET WebForm / MVC 源码分析
- Asp.net MVC源码分析--Action Filter的链式调用
- asp.net mvc源码分析-ActionResult篇 FindView
- ASP.NET MVC中的ActionFilter是如何执行的?
- asp.net mvc源码分析-RenderAction和RenderPartial
- asp.net mvc源码分析-BeginForm方法 和ClientValidationEnabled 属性
- asp.net mvc源码分析-AsyncController