实现MVC自定义过滤器,自定义Area过滤器,自定义Controller,Action甚至是ViewData过滤器

时间:2023-03-08 20:26:41

MVC开发中几种以AOP方式实现的Filters是非常好用的,默认情况下,我们通过App_Start中的FilterConfig来实现的过滤器注册是全局的,也就是整个应用程序都会使用的,针对单独的Filter我们不得不去单独的Controller或者Action去定义

如图:

实现MVC自定义过滤器,自定义Area过滤器,自定义Controller,Action甚至是ViewData过滤器

那么问题来了,我现在想在FitlerConfig里面去维护所有的过滤器,但是又想实现自定义的过滤器该咋搞,MVC默认不支持!

我们先来看看,MVC默认的Fitlers注册是怎样的
官方源码:GlobalFilterCollection.cs

 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.

 using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc.Filters;
using System.Web.Mvc.Properties; namespace System.Web.Mvc
{
public sealed class GlobalFilterCollection : IEnumerable<Filter>, IFilterProvider
{
private List<Filter> _filters = new List<Filter>(); public int Count
{
get { return _filters.Count; }
} public void Add(object filter)
{
AddInternal(filter, order: null);
} public void Add(object filter, int order)
{
AddInternal(filter, order);
} private void AddInternal(object filter, int? order)
{
ValidateFilterInstance(filter);
_filters.Add(new Filter(filter, FilterScope.Global, order));
} public void Clear()
{
_filters.Clear();
} public bool Contains(object filter)
{
return _filters.Any(f => f.Instance == filter);
} public IEnumerator<Filter> GetEnumerator()
{
return _filters.GetEnumerator();
} IEnumerator IEnumerable.GetEnumerator()
{
return _filters.GetEnumerator();
} IEnumerable<Filter> IFilterProvider.GetFilters(ControllerContext controllerContext,
ActionDescriptor actionDescriptor)
{
return this;
} public void Remove(object filter)
{
_filters.RemoveAll(f => f.Instance == filter);
} private static void ValidateFilterInstance(object instance)
{
if (instance != null && !(
instance is IActionFilter ||
instance is IAuthorizationFilter ||
instance is IExceptionFilter ||
instance is IResultFilter ||
instance is IAuthenticationFilter))
{
throw Error.InvalidOperation(MvcResources.GlobalFilterCollection_UnsupportedFilterInstance,
typeof(IAuthorizationFilter).FullName,
typeof(IActionFilter).FullName,
typeof(IResultFilter).FullName,
typeof(IExceptionFilter).FullName,
typeof(IAuthenticationFilter).FullName);
}
}
}
}

GlobalFilters.cs

 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.

 namespace System.Web.Mvc
{
public static class GlobalFilters
{
static GlobalFilters()
{
Filters = new GlobalFilterCollection();
} public static GlobalFilterCollection Filters { get; private set; }
}
}

再看看,App_Start里面的FilterConfig.cs

 public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}

可以发现,其实是GlobalFilters里面定义了静态的GlobalFIlterCollection对象,然后通过FilterConfig像这个静态的集合注册Filters,那么我们没看到MVC哪调用了这个集合,是的,Global里面是没有明确写出来,但是我们来看看FilterProviders.cs的源码

 namespace System.Web.Mvc
{
public static class FilterProviders
{
static FilterProviders()
{
Providers = new FilterProviderCollection();
Providers.Add(GlobalFilters.Filters);
Providers.Add(new FilterAttributeFilterProvider());
Providers.Add(new ControllerInstanceFilterProvider());
} public static FilterProviderCollection Providers { get; private set; }
}
}

在静态的构造函数中就已经通过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方法
结果如下:
实现MVC自定义过滤器,自定义Area过滤器,自定义Controller,Action甚至是ViewData过滤器

这个就是当初我们所希望实现的效果!

不知道怎么放附件,我直接贴我的代码好了!

 public static class GlobalFilters
{
static GlobalFilters()
{
Filters = new MyFlterCollection();
} public static MyFlterCollection Filters { get; private set; }
} public class MyFlterCollection : IEnumerable<Filter>, IFilterProvider
{
List<FilterItem> items = new List<FilterItem>();
/// <summary>
/// Filter数量
/// </summary>
public int Count
{
get
{
return items.Count;
}
}
/// <summary>
/// 注册全局过滤器
/// </summary>
/// <param name="filter"></param>
public void Add(object filter)
{
Add(null, filter, null);
}
/// <summary>
/// 注册全局过滤器
/// </summary>
/// <param name="filter"></param>
/// <param name="order"></param>
public void Add(object filter, int order)
{
Add(null, filter, order);
}
/// <summary>
/// 注册注册局部规则过滤器
/// </summary>
/// <param name="func"></param>
/// <param name="filter"></param>
public void Add(Func<ControllerContext, ActionDescriptor, bool> func, object filter)
{
Add(func, filter, null);
}
/// <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)
{
if(ValidateFilterInstance(filter))
items.Add(new FilterItem
{
filter = new Filter(filter, FilterScope.Global, order),
func = func
});
}
/// <summary>
/// 获取过滤器
/// </summary>
/// <param name="controllerContext"></param>
/// <param name="actionDescriptor"></param>
/// <returns></returns>
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;
}
}
} public IEnumerator<Filter> GetEnumerator()
{
return this.GetEnumerator();
} System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
} /// <summary>
/// 清除所有过滤器
/// </summary>
public void Clear()
{
items.Clear();
}
/// <summary>
/// 是否包含过滤器
/// </summary>
/// <param name="filter"></param>
/// <returns></returns>
public bool Contains(object filter)
{
return items.Any(t => t.filter.Instance == filter);
}
/// <summary>
/// 删除过滤器
/// </summary>
/// <param name="filter"></param>
public void Remove(object filter)
{
items.RemoveAll(t => t.filter.Instance == filter);
} /// <summary>
/// 验证过滤器是否为IActionFilter,IAuthorizationFilter,IExceptionFilter,IResultFilter
/// </summary>
/// <param name="instance"></param>
/// <returns></returns>
private static bool ValidateFilterInstance(object instance)
{
if (instance == null) return false;
return
instance is IActionFilter ||
instance is IAuthorizationFilter ||
instance is IExceptionFilter ||
instance is IResultFilter;
}
}
/// <summary>
/// 存储
/// </summary>
public class FilterItem
{
public Filter filter { get; set; }
public Func<ControllerContext, ActionDescriptor, bool> func { get; set; }
}

Global.asax的Application_start中

 //FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
MyFilterConfig.RegistGlobalFilters(Geo.Mvc.Provider.GlobalFilters.Filters);
FilterProviders.Providers.Add(Geo.Mvc.Provider.GlobalFilters.Filters);

最后App_Start中的MyFilterConfig.cs

 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) == ;
}, new Filters.TestFilter());
}
}

OK!