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

深入理解ASP.NET MVC(7)

2010-12-01 22:28 239 查看
系列目录

Action的定位

再次回到Controller的ExecuteCore方法,回到action调用的入口:

if (!ActionInvoker.InvokeAction(ControllerContext, actionName))

这里的ActionInvoker是个IActionInvoke,它无疑是负责了所有action的调用逻辑,MVC中默认实现这个接口的是ControllerActionInvoke。可以想象ControllerActionInvoke面临的第一个问题是如何找到与actionName对应的action。

首先,并不是所有的action都合法,需要符合下面条件:


1、Public,非static

2、非Controller或其基类定义的方法,比如ToString(),GetHashcode()

3、不能是特殊名字System.Reflection.MethodBase的IsSpecialName标志,例如构造函数,属性包装器,事件包装器

4、具有泛型参数的方法尽管会被认为是action,但框架试图执行这样的action时会只是抛出异常。


其次,MVC为action的查找过程设计了两种“选择器”

ActionNameSelectorAttribute

ActionMethodSelectorAttribute

如果对此比较迷茫的话,看了他们的派生特性,你也许就明白了:









我们常用ActionNameAttribute来“伪装”;用HttpPostAttributeHttpGetAttribute来说明某个action符合的特定的http行为;用NoAction隐藏我们不想“暴露给url”的方法…其实这些行为的原理便是利用MVC为我们提供的action选择的机制。下面这张图说明了这个过程的完成逻辑:





ContollerActionInvoker.InvokeAction在内部创建一个ReflectedControllerDescriptor,并调用其FindAction方法,这个对象的FindAction负责调用一个ActionMethodSelector对象实现上述逻辑,并在最后返回一个ReflectedActionDescriptor。ActionMethodSelector对象故名思意,原理上用反射执行上述过程,执行的结果要么返回一个MethodInfo,要么返回null,要么抛出异常。ReflectedControllerDescriptor对返回值判断,如果是null,则也返回null;如果是MethodInfo,则将其包装成ReflectedActionDescriptor返回。对于外面的InvokeAction方法来说只要ReflectedControllerDescriptor返回的ReflectedActionDescriptor为空就返回false,否则继续。Controller负责对返回false的情况调用HandleUnknownAction,该方法默认产生404错误,我们可以重写它。

在回过头来看看上图的逻辑,不难得到这样一个事实:ActionNameSelectorAttribute优先于ActionMethodSelectorAttribute,ActionMethodSelectorAttribute优先于没有ActionMethodSelectorAttribute特性的方法

更多关于这部分源码的细节,可以参考:通过源代码研究ASP.NET MVC中的Controller和View(六)

MVC的内建过滤器

ActionDescriptor(ReflectedActionDescriptor)返回后,ContollerActionInvoker开始执行action,但是在执行action前还有一些额外的步骤,那就是过滤。以下四个是MVC内建的过滤接口:

IActionFilter

IAuthorizationFilter

IExceptionFilter

IResultFilter

这四个Filter会被ControllerActionInvoker框架综合考量,下面的伪代码说明了ControllerActionInvoker处理他们的逻辑顺序:

try
{
//依次执行IAuthorizationFilter
Run each IAuthorizationFilter's OnAuthorization() method
//所有的IAuthorizationFilter都返回null而不是ActionResult
if(none of the IAuthorizationFilters cancelled execution)
{
Run each IActionFilter's OnActionExecuting() method
Run the action method
//注意到这里按照反转顺序进行
Run each IActionFilter's OnActionExecuted() method (in reverse order)
Run each IResultFilter's OnResultExecuting() method
Run the action result
//注意到这里按照反转顺序进行
Run each IResultFilter's OnResultExecuted() method (in reverse order)
}
//有IAuthorizationFilter返回ActionResult
else
{
Run any action result set by the authorization filters
}
}
catch(exception not handled by any action or result filter)
{
//注意到IExceptionFilter处理的异常只在这个try catch块中
Run each IExceptionFilter's OnException() method
Run any action result set by the exception filters
}

需要注意的事项,在代码中都已经给出注释,在后面一节中,将讨论其中的某些细节。

MVC中与这四个接口相关的特性如下:





我们熟悉的有AuthorizeOutputCacheChildAction等。曾经,对于这些形形色色的Attribute,我都不能很好的理解和归类,现在总算是找它们各自的归宿了。

下一节,将针对这四个过滤器接口深入讨论一些细节问题。

劳动果实,转载请注明出处:/article/5007756.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: