MVC 请求处理流程(二)
[上一篇]中我们说到了对象AsyncControllerActionInvoker,在Controller的ExecuteCore方法中调用AsyncControllerActionInvoker对象的InvokeAction方法来执行动作方法.
public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
if (string.IsNullOrEmpty(actionName))
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);
ActionDescriptor action = this.FindAction(controllerContext, controllerDescriptor, actionName);
if (action == null)
return false;
FilterInfo filters = this.GetFilters(controllerContext, action);
try
{
AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, action);
if (authorizationContext.Result != null)
{
this.InvokeActionResult(controllerContext, authorizationContext.Result);
}
else
{
if (controllerContext.Controller.ValidateRequest)
ControllerActionInvoker.ValidateRequest(controllerContext);
IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, action);
ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, action, parameterValues);
this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, actionExecutedContext.Result);
}
}
catch (ThreadAbortException ex)
{
throw;
}
catch (Exception ex)
{
ExceptionContext exceptionContext = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, ex);
if (!exceptionContext.ExceptionHandled)
throw;
else
this.InvokeActionResult(controllerContext, exceptionContext.Result);
}
return true;
}
这个方法是在AsyncControllerActionInvoker的基类ControllerActionInvoker中实现的,而且做了很做工作,我们来逐步分解这个方法,首先,获取控制器的描述对象方法
protected virtual ControllerDescriptor GetControllerDescriptor(ControllerContext controllerContext)
{
Type controllerType = controllerContext.Controller.GetType();
return this.DescriptorCache.GetDescriptor(controllerType, (Func<ControllerDescriptor>) (() => (ControllerDescriptor) new ReflectedControllerDescriptor(controllerType)));
}
在这个方法中,获取Controller描述对象默认为ReflectedControllerDescriptor。然后再根据动作方法名称获取动作描述对象ActionDescriptor,
protected virtual ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
{
return controllerDescriptor.FindAction(controllerContext, actionName);
}
可以看到其实调用的是控制器描述对象的获取动作描述对象的方法,我们根据获取的默认控制器描述对象ReflectedControllerDescriptor,查看它的FindAction:
public override ActionDescriptor FindAction(ControllerContext controllerContext, string actionName)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
if (string.IsNullOrEmpty(actionName))
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
MethodInfo actionMethod = this._selector.FindActionMethod(controllerContext, actionName);
if (actionMethod == (MethodInfo) null)
return (ActionDescriptor) null;
else
return (ActionDescriptor) new ReflectedActionDescriptor(actionMethod, actionName, (ControllerDescriptor) this);
}
返回默认是封装了要调用的方法对象 MethodInfo的ReflectedActionDescriptor对象。
下来一步是根据控制器上下文和动作描述对象获取到应用到动作和控制器上的所有筛选器,并从获取到的所有筛选器中得到授权过滤器,然后对每个授权过滤器调用OnAuthorization方法,判断返回的AuthorizationContext的Result如果不为空,就直接调用动作结果方法InvokeActionResult。如果为空,说明授权都通过了,然后获取动作方法的参数和根据模型绑定器绑定参数值,(这里会涉及到另外一个组件IModelBinder,我们会在后续详细谈论它,在这里我们就只需知道他会根据参数名称从请求的数据中绑定参数值)
protected virtual IDictionary<string, object> GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
Dictionary<string, object> dictionary = new Dictionary<string, object>((IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase);
foreach (ParameterDescriptor parameterDescriptor in actionDescriptor.GetParameters())
dictionary[parameterDescriptor.ParameterName] = this.GetParameterValue(controllerContext, parameterDescriptor);
return (IDictionary<string, object>) dictionary;
}
protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
{
Type parameterType = parameterDescriptor.ParameterType;
IModelBinder modelBinder = this.GetModelBinder(parameterDescriptor);
IValueProvider valueProvider = controllerContext.Controller.ValueProvider;
string str = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;
Predicate<string> propertyFilter = ControllerActionInvoker.GetPropertyFilter(parameterDescriptor);
ModelBindingContext bindingContext = new ModelBindingContext()
{
FallbackToEmptyPrefix = parameterDescriptor.BindingInfo.Prefix == null,
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType((Func<object>) null, parameterType),
ModelName = str,
ModelState = controllerContext.Controller.ViewData.ModelState,
PropertyFilter = propertyFilter,
ValueProvider = valueProvider
};
return modelBinder.BindModel(controllerContext, bindingContext) ?? parameterDescriptor.DefaultValue;
}
再下来根据控制器描述对象,动作描述对象和或取得的参数执行InvokeActionMethod方法:
protected virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
{
object actionReturnValue = actionDescriptor.Execute(controllerContext, parameters);
return this.CreateActionResult(controllerContext, actionDescriptor, actionReturnValue);
}
在这里我们发现方法执行的关键是在actionDescriptor.Execute(controllerContext, parameters),我们知道这个actionDescriptor是个ReflectedActionDescriptor对象,
public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
if (parameters == null)
throw new ArgumentNullException("parameters");
object[] parameters1 = Enumerable.ToArray<object>(Enumerable.Select<ParameterInfo, object>((IEnumerable<ParameterInfo>) this.MethodInfo.GetParameters(), (Func<ParameterInfo, object>) (parameterInfo => ActionDescriptor.ExtractParameterFromDictionary(parameterInfo, parameters, this.MethodInfo))));
return this.DispatcherCache.GetDispatcher(this.MethodInfo).Execute(controllerContext.Controller, parameters1);
}
最后一步,我们发现调用的是ActionMethodDispatcher对象(这个是个内部对象,它封装了我们要调用的方法对象methodInfo)的Execute方法
public object Execute(ControllerBase controller, object[] parameters)
{
return this._executor(controller, parameters);
}
,我们发现,它是把我们当前调用的controller对象和要调用的方法的参数作为参数进行调用的,而_executor是个委托对象,我们可以通过ActionMethodDispatcher的构造函数看到它的值
public ActionMethodDispatcher(MethodInfo methodInfo)
{
this._executor = ActionMethodDispatcher.GetExecutor(methodInfo);
this.MethodInfo = methodInfo;
}
来自于方法GetExecutor,继续
private static ActionMethodDispatcher.ActionExecutor GetExecutor(MethodInfo methodInfo)
{
ParameterExpression parameterExpression1 = Expression.Parameter(typeof (ControllerBase), "controller");
ParameterExpression parameterExpression2 = Expression.Parameter(typeof (object[]), "parameters");
List<Expression> list = new List<Expression>();
ParameterInfo[] parameters = methodInfo.GetParameters();
for (int index = 0; index < parameters.Length; ++index)
{
ParameterInfo parameterInfo = parameters[index];
UnaryExpression unaryExpression = Expression.Convert((Expression) Expression.ArrayIndex((Expression) parameterExpression2, (Expression) Expression.Constant((object) index)), parameterInfo.ParameterType);
list.Add((Expression) unaryExpression);
}
MethodCallExpression methodCallExpression = Expression.Call((Expression) (!methodInfo.IsStatic ? Expression.Convert((Expression) parameterExpression1, methodInfo.ReflectedType) : (UnaryExpression) null), methodInfo, (IEnumerable<Expression>) list);
if (methodCallExpression.Type == typeof (void))
return ActionMethodDispatcher.WrapVoidAction(Expression.Lambda<ActionMethodDispatcher.VoidActionExecutor>((Expression) methodCallExpression, new ParameterExpression[2]
{
parameterExpression1,
parameterExpression2
}).Compile());
else
return Expression.Lambda<ActionMethodDispatcher.ActionExecutor>((Expression) Expression.Convert((Expression) methodCallExpression, typeof (object)), new ParameterExpression[2]
{
parameterExpression1,
parameterExpression2
}).Compile();
}
这个方法是把我们传进来的要调用的methodInfo对象,构建了一个表达式形式如:(ControllerBase,object[])=>ControllerBase.MethodInfo(object[]),我们发现他就是构造了_executor类型的委托的表达式,而它的类型为
private delegate object ActionExecutor(ControllerBase controller, object[] parameters);
它的调用则为ActionMethodDispatcher.Execute()方法,就是调用了当前controller对象中定义的方法,得到返回值
protected virtual ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)
{
if (actionReturnValue == null)
return (ActionResult) new EmptyResult();
ActionResult actionResult = actionReturnValue as ActionResult;
if (actionResult == null)
actionResult = (ActionResult) new ContentResult()
{
Content = Convert.ToString(actionReturnValue, (IFormatProvider) CultureInfo.InvariantCulture)
};
return actionResult;
}
得到执行结果对象ActionResult,把这个对象封装到ActionExecutedContext对象中返回,然后调用InvokeActionResultWithFilters方法,最终都会调用的方法就是InvokeActionResult方法,而这个方法中
protected virtual void InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
{
actionResult.ExecuteResult(controllerContext);
}
会涉及到另外一个对象ActionResult,这个对象会把最终的结果呈现给客户端!
MVC 请求处理流程(二)的更多相关文章
- ASP.Net请求处理机制初步探索之旅 - Part 5 ASP.Net MVC请求处理流程
好听的歌 我一直觉得看一篇文章再听一首好听的歌,真是种享受.于是,我在这里嵌入一首好听的歌,当然你觉得不想听的话可以点击停止,歌曲 from 王菲 <梦中人>: --> 开篇:上一篇 ...
- ASP.Net MVC请求处理流程
ASP.Net MVC请求处理流程 好听的歌 我一直觉得看一篇文章再听一首好听的歌,真是种享受.于是,我在这里嵌入一首好听的歌,当然你觉得不想听的话可以点击停止,歌曲 from 王菲 <梦中人& ...
- asp.net mvc 请求处理流程,记录一下。
asp.net mvc 请求处理流程,记录一下.
- Spring MVC 请求处理流程概览
SpringMVC工作流程 图一:请求流程概述 图二:请求在每个组件的处理 解释Spring工作流程 1.用户向服务器发送请求,请求被spring前端控制Servelt DispatcherServe ...
- Spring MVC请求处理流程
从web.xml中 servlet的配置开始, 根据servlet拦截的url-parttern,来进行请求转发 Spring MVC工作流程图 图一 图二 Spring工作流程描述 ...
- Spring mvc请求处理流程详解(一)之视图解析
本文链接:https://blog.csdn.net/lchpersonal521/article/details/53112728 前言 Spring mvc框架相信很多人都很熟悉了,关于这方面 ...
- MVC 请求处理流程(一)
路由系统先获取路由数据,在实现了IHttpModule接口的UrlRoutingModule对象中通过注册HttpApplication的PostResolveRequestCache来解析路由数据并 ...
- ASP.NET的MVC请求处理流程
1.用户打开浏览器,在地址栏输入某个网址的URL并回车,浏览器便开始像该URL指定的服务器发起HTTP请求 .2.服务器的网站服务系统(IIS)接收到该请求,先检查自己是否认识该类请求,如果认识就直接 ...
- 2017.3.31 spring mvc教程(二)核心流程及配置详解
学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...
随机推荐
- SSAS 部署失败 总结
今天部署微软官方的SSAS实例AdventureWorks Multidimensional Models SQL Server 2012到本地SQL SERVER数据库,报了好几个错误.总结一下给大 ...
- iOS 动画组
其实早在一个多月以前就已经实现了动作组播放的功能,不过当时感觉好像没有什么难度并没有放在心上,今天突然要用到动画组,发现已经忘记了,所以又将原来的代码翻出来看了下.最后决定还是写下来,以备不时之需.动 ...
- Redis在JAVA中的运用(工具类)
最近项目需要用redis在中间做缓存所以写了一个工具类作为练习用 redis版本:redis_version:3.0.504 用到阿里的解析JSON的库:fastjson import org.apa ...
- 【转】Expire Google Drive Files 让Google Docs云盘共享连接在指定时间后自动失效
最近在清理Google Docs中之前共享过的文件链接,发现Google Docs多人协作共享过的链接会一直存在,在实际操作中较不灵活.正好订阅的RSS推送了Pseric写的这篇文章 - Expire ...
- 【安全测试】WebGoat安装
参考资料:http://wenku.baidu.com/link?url=Qg8GOqw6-CK92-3Dgrm608TlJjDtKMLU9ZlC73Js9LD2FZFgqdHEfJ2sTIRCae_ ...
- python的字符串内建函数
http://www.ziqiangxuetang.com/python/python-strings.html
- 关于favicon.ico,shortcut icon,icon
引入一篇文章.关于favicon.ico二三事. http://www.cnblogs.com/LoveJenny/archive/2012/05/22/2512683.html 一直对favicon ...
- web storage和cookie的区别
Web Storage的概念和cookie相似,区别是它是为了更大容量存储设计的.Cookie的大小是受限的,并且每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽,另外co ...
- ArcGIS Engine控件运行许可(转)
ArcGIS Engine控件运行许可 Runtime绑定: 在ArcGIS Engine10.0中,许可方式发生了一定的变化,ArcGis10有一个新的要求---runtime绑定.就是在任何A ...
- [MISSAJJ原创] UITableViewCell移动及翻转出现的3D动画效果[58同城cell移动效果]
2015-11-20 很喜欢在安静的状态, 听着音乐,敲着键盘, 和代码们浓情对话, 每一份代码的积累, 都让自己觉得很充实快乐!Y(^_^)Y. 看到58同城app的cell有动画移动出现的特效,很 ...