Configurable Global Action Filters for ASP.NET MVC

ASP.NET MVC 3.0 introduces global action filters - an easy way to apply an action filter to every action in an MVC application. All you need to do is register the filters during application startup:

protected void Application_Start()
{
    ...
    GlobalFilters.Filters.Add(new HandleErrorAttribute());
    GlobalFilters.Filters.Add(new FooFilter());
    GlobalFilters.Filters.Add(new BarFilter());
    ...
}

But what if you wanted to add (or remove) filters through configuration?

<configSections>
  <section name="filters" 
           type="ConfigurableFilters.FiltersSettings, AssemblyName "/> 
</configSections>
...
<filters>
  <add type="System.Web.Mvc.HandleErrorAttribute, System.Web.Mvc..." />
  <add type="ConfigurableFilters.BarFilter, AssemblyName" />
  <add type="ConfigurableFilters.FooFilter, AssemblyName" />
</filters>

In that case you'll need a ConfigurationElement.

public class FilterAction : ConfigurationElement
{
    [ConfigurationProperty("type", IsRequired = true, IsKey = true)]
    public string Type 
    {
        get { return base["type"] as string; }
        set { base["type"] = value; }
    }
}

And a ConfigurationElementCollection.

public class FilterActionCollection : ConfigurationElementCollection
{       
    protected override ConfigurationElement CreateNewElement()
    {
        return new FilterAction();
    }

    protected override object GetElementKey(ConfigurationElement element)
    {            
        return ((FilterAction) element).Type;
    }
}

And a ConfigurationSection.

public class FiltersSettings : ConfigurationSection
{
    public static FiltersSettings Settings
    {
        get
        {
            var section = ConfigurationManager.GetSection("filters")
                          as FiltersSettings;
            return section ?? new FiltersSettings();                
        }
    }

    [ConfigurationProperty("", IsDefaultCollection = true)]
    public FilterActionCollection Filters
    {
        get
        {
            return base[_filtersProperty] as FilterActionCollection;
        }
        set
        {
            base[_filtersProperty] = value;
        }
    }

    private readonly ConfigurationProperty _filtersProperty = 
        new ConfigurationProperty(
            null, typeof (FilterActionCollection), null, 
            ConfigurationPropertyOptions.IsDefaultCollection);
}

One way to apply the configured filters is to use the following code during application startup:

var filters = FiltersSettings.Settings.Filters;
foreach (var filter in filters.Cast<FilterAction>())
{
    var filterType = Type.GetType(filter.Type);
    GlobalFilters.Filters.Add(Activator.CreateInstance(filterType));
}

Another approach is to implement a filter provider. We'll take a look at the provider approach tomorrow.

Print | posted @ Tuesday, January 18, 2011 9:12 AM

Comments on this entry:

Gravatar # re: Configurable Global Action Filters for ASP.NET MVC
by Domenic Denicola at 1/18/2011 7:42 PM

Noteworthy related reading:

bradwilson.typepad.com/...

Strangely enough ASP.NET MVC 3 doesn't use service location for global filters, so you do need stuff like this. (Which is sad, because I hate those configuration-related classes.) But I think manually locating them might be better:

public interface IGlobalFilter {}

...

var filters = ServiceLocator.Current.GetAllInstances<IGlobalFilter>();

foreach (var filter in filters)
{
GlobalFilters.Filters.Add(filter);
}

...

Then configure your DI container to map IGlobalFilter to the appropriate set of types. Modify code to fit if you're not using the Comon Service Locator API.
  
Gravatar # re: Configurable Global Action Filters for ASP.NET MVC
by scott at 1/18/2011 7:52 PM

@Domenic - yes, this is the subject of tomorrow's post (and the day after, too, actually).
  
Gravatar # re: Configurable Global Action Filters for ASP.NET MVC
by Jeff at 1/28/2011 7:59 PM

Ah, haven't seen filters used in this way yet. Given this, your previous post makes a lot more sense now. Cool, thanks :)
  
Comments have been closed on this topic.
Scott Allen
Posts - 869
Comments - 4493
Stories - 14