Dependency Injection in attributes

James picture James · Apr 28, 2015 · Viewed 20k times · Source

I am trying to inject a dependency into a custom AuthorizeAttribute as follows:

public class UserCanAccessArea : AuthorizeAttribute
{
    readonly IPermissionService permissionService;

    public UserCanAccessArea() :
        this(DependencyResolver.Current.GetService<IPermissionService>()) { }

    public UserCanAccessArea(IPermissionService permissionService)
    {
        this.permissionService = permissionService;
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        string AreaID =
            httpContext.Request.RequestContext.RouteData.Values["AreaID"] as string;

        bool isAuthorized = false;

        if (base.AuthorizeCore(httpContext))
            isAuthorized = permissionService.UserCanAccessArea(AreaID, httpContext.User);

        return isAuthorized;
    }
}

This works but seems to be resolving as a singleton meaning I get the problems described in my pervious question

What I'd like to do is use property injection but as my Attribute itself is not resolved by Unity I'm unable to find a way to configure the container to intercept and resolve a property. I have tried the following:

public class UserCanAccessArea : AuthorizeAttribute
{
    public IPermissionService permissionService { get; set; }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        string AreaID =
            httpContext.Request.RequestContext.RouteData.Values["AreaID"] as string;

        bool isAuthorized = false;

        if (base.AuthorizeCore(httpContext))
            isAuthorized = permissionService.UserCanAccessArea(AreaID, httpContext.User);

        return isAuthorized;
    }
}

Container:

container.RegisterType<UserCanAccessArea>(new InjectionProperty("permissionService"));

But the property is always null at runtime.

Has anyone achieved this and if so do you have an example?

Answer

Steven picture Steven · Apr 28, 2015

You should prevent doing dependency injection into attributes completely. The reason for this is explained in this article: Dependency Injection in Attributes: don’t do it!. In summary the article explains that:

  • Constructor injection is not possible, because creation of an Attribute instance cannot be intercepted; the CLR is in control.
  • The use of property injection is fragile, since it results in Temporal Coupling, which should be prevented.
  • Dependency injection into attributes makes it impossible to verify the correctness of the container's configuration.
  • Frameworks like MVC and Web API cache attributes, making it very easy to accidentally create captive dependencies causing bugs.

You have two choices here:

  1. Make the attributes passive, by splitting the data (the attribute) from its behavior (the service) as explained in the referenced article and this related article from Mark Seemann.
  2. Turn your attributes into humble objects as explained in this answer. This means you:
    1. extract all logic from the attribute into a custom service that contains all dependencies.
    2. Register that service in your container.
    3. let the attribute's method (AuthorizeCore in your case) do nothing more than resolving the service from the service locator / DependencyResolver and call the service's method. Important to note here is that you cannot do constructor injection, property injection and the service cannot be stored in the attributes private state (as you already noticed).

Which option to use:

  • Use option 1 if you are very keen into keeping your design clean, or you have more than a few attributes that you need to apply this way, or you want to apply attributes are defined in an assembly that doesn't depend on System.Web.Mvc.
  • Use option 2 otherwise.