MVC开发中几种以AOP方式实现的Filters是非常好用的,默认情况下,我们通过App_Start中的FilterConfig来实现的过滤器注册是全局的,也就是整个应用程序都会使用的,针对单独的Filter我们不得不去单独的Controller或者Action去定义
如图:
那么问题来了,我现在想在FitlerConfig里面去维护所有的过滤器,但是又想实现自定义的过滤器该咋搞,MVC默认不支持!
我们先来看看,MVC默认的Fitlers注册是怎样的
官方源码:GlobalFilterCollection.cs
GlobalFilters.cs
再看看,App_Start里面的FilterConfig.cs
可以发现,其实是GlobalFilters里面定义了静态的GlobalFIlterCollection对象,然后通过FilterConfig像这个静态的集合注册Filters,那么我们没看到MVC哪调用了这个集合,是的,Global里面是没有明确写出来,但是我们来看看FilterProviders.cs的源码
在静态的构造函数中就已经通过Providers.Add(GlobalFilters.Filters);把GlobalFilters.Filters集合给添加进去了,然后MVC每次请求会调用IFilterProvider.GetFilters,那为什么自带的GlobalFilterCollection就不能实现自定义的过滤器呢,请看最上面GlobalFilterCollection.cs的GetFilters代码,他直接返回所有的Filters,而且这个类不能重写,好吧!我们来自己写一个实现自定义过滤器!
可以完全照搬GlobalFilterCollection.cs,GlobalFilters.cs代码,然后根据自己的需求改改
这里我们要通过GetFilters实现自己的筛选规则
看看原始方法源码:
1
2
3
4
5
|
IEnumerable<Filter> IFilterProvider.GetFilters(ControllerContext controllerContext,
ActionDescriptor actionDescriptor)
{
return
this
;
}
|
这个方法传进来两个参数:ControllerContext和ActionDescriptor
我们添加Add方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
/// <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
});
}
|
1
|
FilterItem是我自己写的一个类,用来存储设置的Filters跟规则的Func
|
1
2
3
4
5
|
public
class
FilterItem
{
public
Filter filter {
get
;
set
; }
public
Func<ControllerContext, ActionDescriptor,
bool
> func {
get
;
set
; }
}
|
然后改造GetFilters方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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
1
2
3
4
5
6
7
8
9
|
public
ActionResult Index()
{
return
Content(
"Index"
);
}
public
ActionResult Test()
{
return
Content(
"test"
);
}
|
自己随便写个Filter测试
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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注册
1
2
3
4
5
6
7
8
9
10
11
|
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());
}
}
|
这个就是当初我们所希望实现的效果!
不知道怎么放附件,我直接贴我的代码好了!
Global.asax的Application_start中
最后App_Start中的MyFilterConfig.cs
OK!