11

How can i inject the following dependencies ??

public class Authenticate : AuthorizeAttribute
{
        [Dependency]
        public IAuthenticate AuthenticateLibrary { get; set; }

        [Dependency]
        public ILibrary BaseLibrary { get; set; }

        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
        }
}

I am using Unity 2 to inject all the controllers. Is there a tutorial for Unity 2 and injecting dependencies into filters?

Tallmaris
  • 7,605
  • 3
  • 28
  • 58
Patrick
  • 5,442
  • 9
  • 53
  • 104

3 Answers3

13

Brad Wilson has a good series on Service Location which includes how to create your own filter provider that can support dependency injection: http://bradwilson.typepad.com/blog/2010/07/service-location-pt4-filters.html (Scroll down to the section "Adding Dependency Injection to Filters").

  • Copy the code he provides for the UnityFilterAttributeFilterProvider.cs.

UnitFilterAttributeFilterProvider.cs

using System.Collections.Generic;
using System.Web.Mvc;
using Microsoft.Practices.Unity;

public class UnityFilterAttributeFilterProvider : FilterAttributeFilterProvider {
    private IUnityContainer _container;

    public UnityFilterAttributeFilterProvider(IUnityContainer container) {
        _container = container;
    }

    protected override IEnumerable<FilterAttribute> GetControllerAttributes(
                ControllerContext controllerContext,
                ActionDescriptor actionDescriptor) {

        var attributes = base.GetControllerAttributes(controllerContext,
                                                      actionDescriptor);
        foreach (var attribute in attributes) {
            _container.BuildUp(attribute.GetType(), attribute);
        }

        return attributes;
    }

    protected override IEnumerable<FilterAttribute> GetActionAttributes(
                ControllerContext controllerContext,
                ActionDescriptor actionDescriptor) {

        var attributes = base.GetActionAttributes(controllerContext,
                                                  actionDescriptor);
        foreach (var attribute in attributes) {
            _container.BuildUp(attribute.GetType(), attribute);
        }

        return attributes;
    }
}
  • Modify the Application_Start of the global.asax.cs to make the UnityFilterAttributeFilterProvider the filter provider for your MVC app.

.

protected void Application_Start() {
    // ...

    var oldProvider = FilterProviders.Providers.Single(
        f => f is FilterAttributeFilterProvider
    );
    FilterProviders.Providers.Remove(oldProvider);

    var container = new UnityContainer();
    var provider = new UnityFilterAttributeFilterProvider(container);
    FilterProviders.Providers.Add(provider);

    // ...
}
  • Decorate the properties that you want Unity to inject a value for with the [Dependency] attribute. And then you should be good to go.
John Allers
  • 3,052
  • 2
  • 30
  • 36
9

Since Unity is not instantiating the Filters, it cannot inject them. You would have to resort to service locator pattern such as in the following:

public class Authenticate : AuthorizeAttribute
{
    public IAuthenticate AuthenticateLibrary { get; private set; }

    public ILibrary BaseLibrary { get; private set; }

    public Authenticate()
    {
        AuthenticateLibrary = DependencyResolver.Current.GetService<IAuthenticate>();
        BaseLibrary = DependencyResolver.Current.GetService<ILibrary >();
    }
    ...
}
Ethan Cabiac
  • 4,943
  • 20
  • 36
  • If i were to add the ILibrary and IAuthenticate to a normal controller, they are instantiated. So i know that they are registered with unity. – Patrick May 26 '11 at 08:13
  • 2
    @Patrick - it is not about whether they are registered, it is about how they are instantiated. Essentially, the framework is calling `new Authenticate()` which bypasses any DI-Container. – Ethan Cabiac May 26 '11 at 11:25
8

For all people that (like me) arrived here looking for a solution in MVC4 + Unity, although the accepted answers works perfectly, I wanted to add that now you can also simply override the GetFilters method of the FilterAttributeFilterProvider class:

public class CustomFilterProvider : FilterAttributeFilterProvider
{
    private readonly IUnityContainer container;

    public CustomFilterProvider(IUnityContainer container)
    {
        this.container = container;
    }

    public override IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        var filters = base.GetFilters(controllerContext, actionDescriptor);

        var enumerable = filters as IList<Filter> ?? filters.ToList();

        foreach (var filter in enumerable)
        {
            container.BuildUp(filter.Instance.GetType(), filter.Instance);
        }

        return enumerable;
    }
}

Cheers.

Tallmaris
  • 7,605
  • 3
  • 28
  • 58