Dependency injection for filters

Rapha��l Dor�� edited this page Nov 27, 2015 · 9 revisions

MVC3 introduced a completely new pattern to configure filters for controllers and its actions. While injection of filter attributes is still supported it is recommended using this new pattern for filter configuration because it has the advantage to support constructor injection and does not require the InjectAttribute anymore.

First of all you have to create your filter class by implementing one of the filter interfaces e.g. IActionFilter. All the dependencies are added to the constructor. The following example of a logging filter has a logger as dependency and can be configured with the level that is used to log.

public class LogFilter : IActionFilter
{
    private readonly ILog log;
    private readonly Level logLevel;

    public LogFilter(ILog log, Level logLevel)
    {
        this.log = log;
        this.logLevel = logLevel;
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var message = string.Format(
                CultureInfo.InvariantCulture,
                "Executing action {0}.{1}",
                filterContext.ActionDescriptor.ControllerDescriptor.ControllerName,
                filterContext.ActionDescriptor.ActionName),
        this.log.Logger.Log(typeof(LogFilter), this.logLevel, message, null);
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var message = string.Format(
                CultureInfo.InvariantCulture,
                "Executed action {0}.{1}",
                filterContext.ActionDescriptor.ControllerDescriptor.ControllerName,
                filterContext.ActionDescriptor.ActionName),
        this.log.Logger.Log(typeof(LogFilter), this.logLevel, message, null);
    }
}

To apply this filter to an action or controller we need to specify a binding. But unlike other bindings, filters require that BindFilter is used instead of the normal Bind. Additionally, the type of the filter you have to specify the filter scope and the filter order. More information about these two parameters can be found "Brad Wilsons Blog":http://bradwilson.typepad.com/blog/2010/07/service-location-pt4-filters.html.

In the example below the LogFilter is applied to every action and configured with the log level info.

public class LoggingModule : NinjectModule
{    
    public override void Load()
    {
        this.Bind<ILog>().ToMethod(GetLogger);
        this.BindFilter<LogFilter>(FilterScope.Controller, 0)
           .WithConstructorArgument("logLevel", Level.Info);
    }

    private static ILog GetLogger(IContext ctx)
    {
        var filterContext = ctx.Request.ParentRequest.Parameters
            .OfType<FilterContextParameter>().SingleOrDefault();

        return
            LogManager.GetLogger(filterContext == null
                ? ctx.Request.Target.Member.DeclaringType
                : filterContext.ActionDescriptor.ControllerDescriptor.ControllerType);
    }
}

Further Information on this topic: