MVC开发中几种以AOP方式实现的Filters是非常好用的,默认情况下,我们通过App_Start中的FilterConfig来实现的过滤器注册是全局的,也就是整个应用程序都会使用的,针对单独的Filter我们不得不去单独的Controller或者Action去定义
如图:
那么问题来了,我现在想在FitlerConfig里面去维护所有的过滤器,但是又想实现自定义的过滤器该咋搞,MVC默认不支持!
我们先来看看,MVC默认的Fitlers注册是怎样的
官方源码:GlobalFilterCollection.cs
1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. 2 3 using System.Collections; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Web.Mvc.Filters; 7 using System.Web.Mvc.Properties; 8 9 namespace System.Web.Mvc 10 { 11 public sealed class GlobalFilterCollection : IEnumerable<Filter>, IFilterProvider 12 { 13 private List<Filter> _filters = new List<Filter>(); 14 15 public int Count 16 { 17 get { return _filters.Count; } 18 } 19 20 public void Add(object filter) 21 { 22 AddInternal(filter, order: null); 23 } 24 25 public void Add(object filter, int order) 26 { 27 AddInternal(filter, order); 28 } 29 30 private void AddInternal(object filter, int? order) 31 { 32 ValidateFilterInstance(filter); 33 _filters.Add(new Filter(filter, FilterScope.Global, order)); 34 } 35 36 public void Clear() 37 { 38 _filters.Clear(); 39 } 40 41 public bool Contains(object filter) 42 { 43 return _filters.Any(f => f.Instance == filter); 44 } 45 46 public IEnumerator<Filter> GetEnumerator() 47 { 48 return _filters.GetEnumerator(); 49 } 50 51 IEnumerator IEnumerable.GetEnumerator() 52 { 53 return _filters.GetEnumerator(); 54 } 55 56 IEnumerable<Filter> IFilterProvider.GetFilters(ControllerContext controllerContext, 57 ActionDescriptor actionDescriptor) 58 { 59 return this; 60 } 61 62 public void Remove(object filter) 63 { 64 _filters.RemoveAll(f => f.Instance == filter); 65 } 66 67 private static void ValidateFilterInstance(object instance) 68 { 69 if (instance != null && !( 70 instance is IActionFilter || 71 instance is IAuthorizationFilter || 72 instance is IExceptionFilter || 73 instance is IResultFilter || 74 instance is IAuthenticationFilter)) 75 { 76 throw Error.InvalidOperation(MvcResources.GlobalFilterCollection_UnsupportedFilterInstance, 77 typeof(IAuthorizationFilter).FullName, 78 typeof(IActionFilter).FullName, 79 typeof(IResultFilter).FullName, 80 typeof(IExceptionFilter).FullName, 81 typeof(IAuthenticationFilter).FullName); 82 } 83 } 84 } 85 }
GlobalFilters.cs
1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. 2 3 namespace System.Web.Mvc 4 { 5 public static class GlobalFilters 6 { 7 static GlobalFilters() 8 { 9 Filters = new GlobalFilterCollection(); 10 } 11 12 public static GlobalFilterCollection Filters { get; private set; } 13 } 14 }
再看看,App_Start里面的FilterConfig.cs
1 public class FilterConfig 2 { 3 public static void RegisterGlobalFilters(GlobalFilterCollection filters) 4 { 5 filters.Add(new HandleErrorAttribute()); 6 } 7 }
可以发现,其实是GlobalFilters里面定义了静态的GlobalFIlterCollection对象,然后通过FilterConfig像这个静态的集合注册Filters,那么我们没看到MVC哪调用了这个集合,是的,Global里面是没有明确写出来,但是我们来看看FilterProviders.cs的源码
1 namespace System.Web.Mvc 2 { 3 public static class FilterProviders 4 { 5 static FilterProviders() 6 { 7 Providers = new FilterProviderCollection(); 8 Providers.Add(GlobalFilters.Filters); 9 Providers.Add(new FilterAttributeFilterProvider()); 10 Providers.Add(new ControllerInstanceFilterProvider()); 11 } 12 13 public static FilterProviderCollection Providers { get; private set; } 14 } 15 }
在静态的构造函数中就已经通过Providers.Add(GlobalFilters.Filters);把GlobalFilters.Filters集合给添加进去了,然后MVC每次请求会调用IFilterProvider.GetFilters,那为什么自带的GlobalFilterCollection就不能实现自定义的过滤器呢,请看最上面GlobalFilterCollection.cs的GetFilters代码,他直接返回所有的Filters,而且这个类不能重写,好吧!我们来自己写一个实现自定义过滤器!
可以完全照搬GlobalFilterCollection.cs,GlobalFilters.cs代码,然后根据自己的需求改改
这里我们要通过GetFilters实现自己的筛选规则
看看原始方法源码:
IEnumerable<Filter> IFilterProvider.GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { return this; }
这个方法传进来两个参数:ControllerContext和ActionDescriptor
我们添加Add方法
/// <summary> /// 注册注册局部规则过滤器 /// </summary> /// <param name="func"></param> /// <param name="filter"></param> /// <param name="order"></param> public void Add(Func<ControllerContext, ActionDescriptor, bool> func, object filter, int order) { Add(func, filter, order); } private void Add(Func<ControllerContext, ActionDescriptor, bool> func, object filter, int? order) { ValidateFilterInstance(filter); items.Add(new FilterItem { filter = new Filter(filter, FilterScope.Global, order), func = func }); }
FilterItem是我自己写的一个类,用来存储设置的Filters跟规则的Func
public class FilterItem { public Filter filter { get; set; } public Func<ControllerContext, ActionDescriptor, bool> func { get; set; } }
然后改造GetFilters方法
public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { foreach (FilterItem item in items) { if (item.func == null) { yield return item.filter; } else { bool result = item.func(controllerContext, actionDescriptor); if (result) yield return item.filter; } } }
这样在执行GetFilters的时候就会根据注册的所有Filters进行筛选匹配出符合条件的Filters
最后App_Start中自定义FilterConfig注册Filtes
然后在Global添加自定义的Filters注册
FilterProviders.Providers.Add(Geo.Mvc.Provider.GlobalFilters.Filters);
测试:
新建HomeController,写上两个Action分别为Index和Test
public ActionResult Index() { return Content("Index"); } public ActionResult Test() { return Content("test"); }
自己随便写个Filter测试
public class TestFilter : IActionFilter { public void OnActionExecuted(ActionExecutedContext filterContext) { filterContext.HttpContext.Response.Write("执行前!<br/>"); } public void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.HttpContext.Response.Write("执行后!<br/>"); } }
去App_Start中自定义的Filter注册
public class MyFilterConfig { public static void RegistGlobalFilters(Geo.Mvc.Provider.MyFlterCollection filters) { //filters.Add(new Filters.TestFilter()); filters.Add((c, a) => { return string.Compare(a.ActionName, "test", true) == 0; }, new Filters.TestFilter()); } }
最后执行Index跟Test方法
结果如下:
这个就是当初我们所希望实现的效果!
不知道怎么放附件,我直接贴我的代码好了!
1 public static class GlobalFilters 2 { 3 static GlobalFilters() 4 { 5 Filters = new MyFlterCollection(); 6 } 7 8 public static MyFlterCollection Filters { get; private set; } 9 } 10 11 public class MyFlterCollection : IEnumerable<Filter>, IFilterProvider 12 { 13 List<FilterItem> items = new List<FilterItem>(); 14 /// <summary> 15 /// Filter数量 16 /// </summary> 17 public int Count 18 { 19 get 20 { 21 return items.Count; 22 } 23 } 24 /// <summary> 25 /// 注册全局过滤器 26 /// </summary> 27 /// <param name="filter"></param> 28 public void Add(object filter) 29 { 30 Add(null, filter, null); 31 } 32 /// <summary> 33 /// 注册全局过滤器 34 /// </summary> 35 /// <param name="filter"></param> 36 /// <param name="order"></param> 37 public void Add(object filter, int order) 38 { 39 Add(null, filter, order); 40 } 41 /// <summary> 42 /// 注册注册局部规则过滤器 43 /// </summary> 44 /// <param name="func"></param> 45 /// <param name="filter"></param> 46 public void Add(Func<ControllerContext, ActionDescriptor, bool> func, object filter) 47 { 48 Add(func, filter, null); 49 } 50 /// <summary> 51 /// 注册注册局部规则过滤器 52 /// </summary> 53 /// <param name="func"></param> 54 /// <param name="filter"></param> 55 /// <param name="order"></param> 56 public void Add(Func<ControllerContext, ActionDescriptor, bool> func, object filter, int order) 57 { 58 Add(func, filter, order); 59 } 60 61 62 private void Add(Func<ControllerContext, ActionDescriptor, bool> func, object filter, int? order) 63 { 64 if(ValidateFilterInstance(filter)) 65 items.Add(new FilterItem 66 { 67 filter = new Filter(filter, FilterScope.Global, order), 68 func = func 69 }); 70 } 71 /// <summary> 72 /// 获取过滤器 73 /// </summary> 74 /// <param name="controllerContext"></param> 75 /// <param name="actionDescriptor"></param> 76 /// <returns></returns> 77 public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) 78 { 79 foreach (FilterItem item in items) 80 { 81 if (item.func == null) 82 { 83 yield return item.filter; 84 } 85 else 86 { 87 bool result = item.func(controllerContext, actionDescriptor); 88 if (result) 89 yield return item.filter; 90 } 91 } 92 } 93 94 public IEnumerator<Filter> GetEnumerator() 95 { 96 return this.GetEnumerator(); 97 } 98 99 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 100 { 101 return this.GetEnumerator(); 102 } 103 104 /// <summary> 105 /// 清除所有过滤器 106 /// </summary> 107 public void Clear() 108 { 109 items.Clear(); 110 } 111 /// <summary> 112 /// 是否包含过滤器 113 /// </summary> 114 /// <param name="filter"></param> 115 /// <returns></returns> 116 public bool Contains(object filter) 117 { 118 return items.Any(t => t.filter.Instance == filter); 119 } 120 /// <summary> 121 /// 删除过滤器 122 /// </summary> 123 /// <param name="filter"></param> 124 public void Remove(object filter) 125 { 126 items.RemoveAll(t => t.filter.Instance == filter); 127 } 128 129 /// <summary> 130 /// 验证过滤器是否为IActionFilter,IAuthorizationFilter,IExceptionFilter,IResultFilter 131 /// </summary> 132 /// <param name="instance"></param> 133 /// <returns></returns> 134 private static bool ValidateFilterInstance(object instance) 135 { 136 if (instance == null) return false; 137 return 138 instance is IActionFilter || 139 instance is IAuthorizationFilter || 140 instance is IExceptionFilter || 141 instance is IResultFilter; 142 } 143 } 144 /// <summary> 145 /// 存储 146 /// </summary> 147 public class FilterItem 148 { 149 public Filter filter { get; set; } 150 public Func<ControllerContext, ActionDescriptor, bool> func { get; set; } 151 }
Global.asax的Application_start中
1 //FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 2 MyFilterConfig.RegistGlobalFilters(Geo.Mvc.Provider.GlobalFilters.Filters); 3 FilterProviders.Providers.Add(Geo.Mvc.Provider.GlobalFilters.Filters);
最后App_Start中的MyFilterConfig.cs
1 public class MyFilterConfig 2 { 3 public static void RegistGlobalFilters(Geo.Mvc.Provider.MyFlterCollection filters) 4 { 5 //filters.Add(new Filters.TestFilter()); 6 filters.Add((c, a) => 7 { 8 return string.Compare(a.ActionName, "test", true) == 0; 9 }, new Filters.TestFilter()); 10 } 11 }
OK!