Introduction
Last year I wrote about FluentFilters and how to use them with ASP.NET MVC 2 to implement the functionality of global filters. With ASP.NET MVC 3 was added native support for global filters. You can register a global filter by using the GlobalFilters.Filters
static registration endpoint. It works great, but sometimes it would be nice to specify conditions for running the filter like criteria in FluentFlters.
Recently, I updated the library and added a version for ASP.NET MVC 3 in which I implemented the functionality described above. This version was completely rewritten in accordance with the new features of ASP.NET MVC 3. As a result of this, the library became smaller and easier to use.
Please note that the versions for ASP.NET MVC 2 and ASP.NET MVC 3 are different. The assembly for ASP.NET MVC 2 is now located in the /bin/mvc2 folder of the library binary package (to learn how to use it, please read the previous article).
Below, I describe the FluentFilters for ASP.NET MVC 3:
- How to configure the application to work with the library
- How to register filters and specify conditions by criteria
- How to create custom criteria
Let's start
To start using FluentFilters is very simple:
- Download the latest version of the library from the Downloads page at CodePlex.
- Unzip the zip file and add a reference to /bin/mvc3/FluentFilters.dll in your MVC project.
- Instead of steps 1-2, you can use NuGet. Right click on References and click Add Library Package Reference. Click Online on the left side, and in the Search box at the upper right, type in "FluentFilters". Click Install. Alternatively, open the Package Manager Console and type "Install-Package FluentFilters".
- Register the
FluentFiltersCollection
filter provider in Global.asax.cs.
- Use the
FluentFiltersBuider.Filters
static registration endpoint to register a global filter with conditions.
It should look like below:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterProviders.Providers.Add(FluentFiltersBuider.Filters);
RegisterGlobalFilters(GlobalFilters.Filters,
FluentFiltersBuider.Filters);
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterGlobalFilters(GlobalFilterCollection filters,
FluentFilterCollection fluentFilters)
{
filters.Add(new HandleErrorAttribute());
fluentFilters.Add<DisplayTopBannerFilterAttribute>(c => {
c.Require(new AreaFilterCriteria("Blog")).Or(new AreaFilterCriteria("Forum"));
c.Exclude(new ControllerFilterCriteria("Admin")).And(
new AreaFilterCriteria("Forum"));
});
}
Registering filters
To register a filter, you need to call the method FluentFilterCollection.Add()
. The provider has a few method definitions:
void Add<T>()
void Add<T>(int order)
void Add<T>(Action<IFilterCriteriaBuilder> criteria)
void Add<T>(Action<IFilterCriteriaBuilder> criteria, int order)
void Add(object filter, Action<IFilterCriteriaBuilder> criteria)
void Add(object filter, Action<IFilterCriteriaBuilder> criteria, int order)
By using registration, for instance, you can set values for the properties:
fluentFilters.Add( new HandleErrorAttribute() { View = "ErrorPage" },
c => { c.Require(new AreaFilterCriteria("Admin"))} );
Specify conditions
To specify the conditions, you should set the chain of criteria for the filter at registration. Using criteria, you can set whether to execute a filter or not. The library already provides three criteria for use:
ActionFilterCriteria
- filter by specified action
AreaFilterCriteria
- filter by specified area
ControllerFilterCriteria
- filter by specified controller
For one filter, you can only specify two chains of criteria. These are the chains of criteria that are required and which should be excluded.
fluentFilters.Add<CheckAuthenticationAttribute>(c =>
{
c.Require(new AreaFilterCriteria("Blog"));
c.Exclude(new ControllerFilterCriteria("Account"));
});
Chains of criteria are constructed by using the methods And(IFilterCriteria criteria)
and Or(IFilterCriteria criteria)
, which work as conditional logical operators && and ||.
fluentFilters.Add<DisplayTopBannerFilterAttribute>(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"));
});
If using the C# language, then the code above can be understood as (like pseudocode):
if( IsFreeAccountFilterCriteria() || area == "Blog" ||
(area == "Forum" && IsMemberFilterCriteria()) )
{
if(area != "Administrator")
{
DisplayTopBannerFilter();
}
else if(controller != "Account" && action != "LogOn")
{
DisplayTopBannerFilter();
}
}
Creating a custom criteria
To create a custom criteria, you should inherit your class from the FluentFilters.IFilterCriteria
interface and implement only one method Match
. For example, see the source code for ActionFilterCriteria
:
public class ActionFilterCriteria : IFilterCriteria
{
#region Fields
private readonly string _actionName;
#endregion
#region Constructor
public ActionFilterCriteria(string actionName)
{
_actionName = actionName;
}
#endregion
#region Implementation of IActionFilterCriteria
public bool Match(ControllerContext controllerContext,
ActionDescriptor actionDescriptor)
{
return string.Equals(_actionName,
controllerContext.RouteData.GetRequiredString("action"),
StringComparison.OrdinalIgnoreCase);
}
#endregion
}