Skip to content

Dependency injection for filters

hach-que edited this page Oct 15, 2014 · 3 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. To simplify the action filter implemntation The extension provides an AbstractActionFilter.

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 : AbstractActionFilter
{
    private readonly ILog log;
    private readonly string prefix;

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

    public override bool AllowMultiple
    {
        get
        {
            return true;
        }
    }

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        this.log.DebugFormat(
            "Executing action {0}.{1}",
            actionContext.ActionDescriptor.ControllerDescriptor.ControllerName,
            actionContext.ActionDescriptor.ActionName);
    }

    public override void OnActionExecuted(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
    {
        this.log.DebugFormat(
            "Executed action {0}.{1}",
            actionExecutedContext.ActionContext.ActionDescriptor.ControllerDescriptor.ControllerName,
            actionExecutedContext.ActionContext.ActionDescriptor.ActionName);
    }
}

To apply this filter to an action or controller we need to specify a binding. But unlike other bindings, filters require that BindHttpFilter is used instead of the normal Bind. Additionally, the type of the filter you have to specify the filter scope.

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.BindHttpFilter<LogFilter>(FilterScope.Controller)
            .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: