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.
Comments
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.