Fluent Filters - ASP.NET MVC 2 的全局动作过滤器






4.50/5 (4投票s)
这篇文章描述了一个用于 ASP.NET MVC 的小型库,可以用作注册全局过滤器的工具。它类似于 ASP.NET MVC 3 中的全局过滤器,但具有不同的实现和功能。

引言
曾经,在一个用 ASP.NET MVC 2 编写的项目中,我需要实现一种方法来为应用程序中的所有控制器注册动作过滤器,因为如果你想全局执行相同的操作,为每个控制器类指定属性不是很方便,而且缺乏灵活性。后来,我只在 ASP.NET MVC 3 中发现了对此的提及。
在那之后,我决定自己编写类似的功能,为自己设定了一系列必须执行的要求
- 在应用程序中轻松注册过滤器
- 能够向过滤器添加条件
- 能够对过滤器使用依赖注入
我有一个有趣的方法,我决定将所有这些结合到一个单独的库中,以便与他人分享。
你可以在 CodePlex 上的 项目页面 找到最新版本的二进制文件和源代码。工作应用程序示例位于源代码的 src\Samples 文件夹中。
Using the Code
FluentFilters
帮助你在你的 ASP.NET MVC 应用程序中实现全局过滤器功能。全局过滤器是一个将对每个控制器的每个动作运行的过滤器。创建一个自定义过滤器供全局使用非常简单。你所需要做的就是用一个或多个接口实现你的自定义过滤器类,这些接口是四种类型的 ASP.NET MVC 过滤器
IAuthorizationFilter
IActionFilter
IResultFilter
IExceptionFilter
例如,一个过滤器可能看起来像这样
public class CustomFilter: IResultFilter, IAuthorizationFilter
{
#region IResultFilter Members
public void OnResultExecuted(ResultExecutedContext filterContext)
{
// Some logic here ...
}
public void OnResultExecuting(ResultExecutingContext filterContext)
{
// Or here ...
}
#endregion
#region IAuthorizationFilter Members
public void OnAuthorization(AuthorizationContext filterContext)
{
// May be here?
}
#endregion
}
为了使用过滤器,你应该使用类 FluentFiltersBuilder
。如果你在没有控制反转(IoC) 容器的情况下构建 MVC 应用程序,这是推荐的使用方法。 使用 IoC 容器的 FluentFilters
比使用 FluentFiltersBuilder
更好。在这种情况下,你可以管理过滤器对象的创建和生命周期,并使用依赖注入。要实现这一点,你需要执行几个步骤。
- 实现继承
FilterRegistry
类的自定义类,并重写GetFilterInstance
方法以按类型解析对象,而不是创建一个新的对象。这个类将代替FluentFiltersBuilder
用于注册过滤器。 - 创建一个自定义控制器工厂以支持 IoC 容器并注册它。
你可以在源代码的 src\Samples\FluentFilters.Samples.IoC 文件夹中找到带有 IoC 容器的示例应用程序。
对于基本配置,编辑 Global.asax.cs 文件就足够了,如下所示
// Global.asax.cs
using System.Web.Mvc;
using System.Web.Routing;
using FluentFilters;
using FluentFilters.Criteria;
using Website.Core.Filters;
namespace Website
{
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index",
id = UrlParameter.Optional } // Parameter defaults
);
}
private static void RegisterFluentFilters()
{
// Register global filter
FluentFiltersBuilder.Current.Add();
}
private static void RegisterControllerFactory()
{
// Set controller factory
ControllerBuilder.Current.SetControllerFactory
(new FluentFiltersControllerFactory());
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
RegisterFluentFilters();
RegisterControllerFactory();
}
}
}
你可以在方法 RegisterFluentFilters
中看到已注册的过滤器 BrowserDetectionFilter
。
稍后,当你添加全局过滤器供使用时,你可以为每个过滤器设置链式条件。通过条件,你可以设置是否执行过滤器。创建条件也非常简单。 你需要从 IFilterCriteria
接口继承你的自定义条件类,并且只实现方法 Match
。该库已经提供了三个条件供使用
ActionFilterCriteria
- 按指定的动作过滤AreaFilterCriteria
- 按指定区域过滤ControllerFilterCriteria
- 按指定的控制器过滤
例如,下面的代码片段显示了条件 ActionFilterCriteria
的源代码
public class ActionFilterCriteria : IFilterCriteria
{
private readonly string _actionName;
/// <summary>
/// Filter by specified action
/// </summary>
/// <param name="actionName">Name of the action</param>
public ActionFilterCriteria(string actionName)
{
_actionName = actionName;
}
#region Implementation of IActionFilterCriteria
public bool Match(FilterRegistryContext context)
{
return string.Equals(_actionName,
context.ControllerContext.RouteData.GetRequiredString("action"),
StringComparison.OrdinalIgnoreCase);
}
#endregion
}
对于每个过滤器,你可以添加两个链式条件。 这是必需的条件,也应该被排除。如果未指定条件,则将在整个应用程序中执行过滤器。
在下面的代码中,我们为区域 "Blog
" 添加了过滤器 BrowserDetectionFilter
,并为控制器 "Account
" 排除。
FluentFiltersBuilder.Current.Add
(c =>
{
c.Require(new AreaFilterCriteria("Blog")); // Execute if current area "Blog"
c.Exclude(new ControllerFilterCriteria("Account")); // Ignore if current
// controller "Account"
});
你可以通过方法 And(IFilterCriteria criteria)
和 Or(IFilterCriteria criteria)
构建条件链。方法的工作方式类似于条件逻辑运算符 &&
和 ||
。
简化示例
registry.Add<displaytopbannerfilter>(c =>
{
c.Require(new IsFreeAccountFilterCriteria()).Or(new AreaFilterCriteria("Blog")).
Or(new AreaFilterCriteria("Forum")).And(new IsMemberFilterCriteria());
c.Exclude(new AreaFilterCriteria("Administrator")).
Or(new ControllerFilterCriteria("Account")).
And(new ActionFilterCriteria("LogOn"));
});
如果用 C# 语言来说,那么上面的代码可以理解为(类似于伪代码)
if( IsFreeAccountFilterCriteria() || area == "Blog" ||
(area == "Forum" && IsMemberFilterCriteria()) )
{
if(area != "Administrator")
{
DisplayTopBannerFilter();
}
else if(controller != "Account" && action != "LogOn")
{
DisplayTopBannerFilter();
}
}
历史
- 2010 年 11 月 4 日:初始版本
- 2010 年 11 月 5 日:更新文章