运行我们的程序之后会在浏览器中呈现如图7-5所示的结果。我们可以清楚地看到,不仅仅应用在自身Action方法的FilterAttribute会应用到目标Action上,应用在Controller类的FilterAttribute、全局注册的Filter以及Controller对象本身体现的Filter都回最终应用在所有的Action上面。
上图将应用于Action方法Data的4个Filter的Order和Scope属性显示出来。我们在前面提到这两个属性决定了同类筛选器执行的顺序,我们现在利用这个程序要证实这一点。为此我们需要对FilterBaseAttribute作如下的修改,在OnActionExecuting中我们将当前执行的FilterAttribute的类型的方法名呈现出来。
public abstract class FilterBaseAttribute:FilterAttribute, IActionFilter { public void OnActionExecuted(ActionExecutedContext filterContext) {} public void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.HttpContext.Response.Write(string.Format("{0}.OnActionExecuting()<br/>", this.GetType())); } }
然后我们按照相同的方式重写了HomeController的OnActionExecuting方法,将HomeController自身的类型的当前方法名称呈现出来。
[Foo] public class HomeController : Controller { //其他成员 protected override void OnActionExecuting(ActionExecutingContext filterContext) { Response.Write("HomeController.OnActionExecuting()<br/>"); } [Bar] public void Data() { } }
我们再次运行我们的程序,并在浏览器上指定正确的地址访问定义在HomeController的Action方法Data,会在浏览器中呈现如下图所示的结果。输出的结果体现了应用到Action方法Data上的四个ActionFilter执行的顺序,而这是和Filter对应的Order和Scope属性值是一致的。
关于Filter的提供还另一个值得深究的问题:我们在定义FilterAttribute的时候可以将应用在该类型上的AttributeUsageAttribute的AllowMultiple属性设置为False使它只能在同一个目标元素上应用一次。但是,我们依然可以在Action方法和所在的Controller类型上应用它们,甚至可以将它们注册为全局Filter,那么这些FilterAttribute都将有效吗?
我们现在就来通过实例来验证这一点。现在我们删除所有的FilterAttribute,定义如下一个类型为FooAttribute的ActionFilter,我们将应用在它上面的AttributeUsageAttribute特性的AllowMultiple属性设置为False。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class FooAttribute : FilterAttribute, IActionFilter { public void OnActionExecuted(ActionExecutedContext filterContext) { } public void OnActionExecuting(ActionExecutingContext filterContext) { } }
现在我们将该FooAttribute特性同时应用在HomeController类型和Action方法Data上,然后在Global.asax中注册一个针对FooAttribute特性的全局Filter。
[Foo] public class HomeController : Controller { //其他成员 [Foo] public void Data() { } } public class MvcApplication : System.Web.HttpApplication { //其他成员 protected void Application_Start() { //其他操作 //RegisterGlobalFilters(GlobalFilters.Filters); GlobalFilters.Filters.Add(new FooAttribute()); } }
现在我们直接运行我们的程序,开启的浏览器中会呈现出如图7-7所示的结果。可以清楚地看到虽然我们 在三个地方注册了FooAttribute,但是由于该特性的AllowMultiple属性为False,所以只有其中一个FooAttribute最终是有效的。
对于AllowMultiple属性为False的FilterAttribute来说,如果我们以不同的Scope注册了多个,最终有效的是哪个呢?从上图可以看出,应用在Action方法(Scope为Action)上的FooAttribute是有效的。其实具体的逻辑是这样的:所有被创建的Filter按照Order+Scope进行排序(即Filter执行的顺序),取排在最后一个。对于我们的例子来说,提供的三个Filter具有相同的Order属性值(-1),所有最终会按照Scope(Scope、Controller和Action)进行排序,排在最后一个的自然是Scope为Action的Filter。