Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency Injection in attributes

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?

like image 792
James Avatar asked Apr 28 '15 09:04

James


People also ask

How do you inject attributes?

In your Startup, register your provider. Use constructor injection in the provider, and pass those dependencies to the attribute. Create an attribute with public setters that can receive dependencies. Apply the attribute to a controller or an action.

What is dependency injection with example?

Dependency injection (DI) is a technique widely used in programming and well suited to Android development. By following the principles of DI, you lay the groundwork for good app architecture. Implementing dependency injection provides you with the following advantages: Reusability of code.

What is dependency attribute?

The ability for some attributes to control the behavior of other attributes is known as attribute dependency. An attribute dependency rule defines the effect that a source attribute value has on one or more target attribute values.


1 Answers

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.
like image 199
Steven Avatar answered Oct 04 '22 07:10

Steven