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.不知道版本上有没有变 ...
随机推荐
- Javascript实现二级select联动
1.js cities = new Object(); cities['河北省']=new Array('石家庄', '张家口市', '承德市', '秦皇岛市', '唐山市', '廊坊市', '保定市 ...
- monkeyrunner自动化测试
通过MonkeyRunner遍历apk文件夹里的apk文件,实现自动安装应用,打开应用,截图,将截图与提前准备好的基线图做对比,对比相似度达到90%时,则对比通过,然后自动卸载应用,进入下一个APK文 ...
- jQuery Mobile学习日记之HelloWorld
这里是本人学习jQuery Mobile的过程,主要用于记录,过程中有不对的地方或不严谨的地方,欢予以指出纠正,非常感谢! 1.首先是下载安装以下文件: [Opera Mobile Emulator] ...
- shell算数运算
((i=$j+$k)) 等价于 i=`expr $j + $k`((i=$j-$k)) 等价于 i=`expr $j -$k`((i=$j*$k)) 等价于 i=`exp ...
- <python 深入理解>变量交换x,y=y,x实现机制--元组
python中有一种赋值机制即多元赋值,采用这种方式赋值时,等号两边的对象都是元组并且元组的小括号是可选的.通常形式为 x, y, z = 1, 2, 'a string' 等同于 (x, y, z) ...
- 工作需求——JQ小效果分享下
一.文字索引效果展示: html布局代码 <ul class="n_areaList"> <li> <h5>当前选择区域</h5> ...
- 关于不断刷新界面jsp+ajax
jsp主要就是用之前的jsonArray读取 ajax可以设置个定时器,然后设置的方法,至于方法是今天学习到的 function ajax(method,data,url,success){ var ...
- 测试一下Word发布刚刚发现通过Word 可以直接发Blog 感觉很新奇,先看看,如果可以呢,将发通知的改了。
刚刚发现通过Word 可以直接发Blog 感觉很新奇,先看看,如果可以呢,将发通知的改了. 刚刚发现通过Word 可以直接发Blog 感觉很新奇,先看看,如果可以呢,将发通知的改了. ...
- Ext4 ComboBox组件使用
先来看例子: Ext.define('schoolModel', { extend: 'Ext.data.Model', fields: [{ name: 'id', type: 'string' ...
- AutoHotkey(AHK)
这是2009年用过的一个软件,自动键盘执行的一个东西,能提高效率,代替人工击键和鼠标操作,现在中文化很好了,如下地址是中文文档 http://ahkcn.sourceforge.net/docs/Tu ...