Dependency Injection in attributes
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:
- 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.
- Turn your attributes into humble objects as explained in this answer. This means you:
- extract all logic from the attribute into a custom service that contains all dependencies.
- Register that service in your container.
- 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.
In ASP.NET Core, this is now possible by either creating a custom attribute, implementing IFilterFactory, or by using TypeFilterAttribute, as well as ServiceFilterAttribute.
Both implement IFilterFactory
and do what you'd normally do in your custom attribute implementing IFilterFactory
, the only difference is that they support ordering (which you can add if you wish in your custom attribute).
But more specifically - ServiceFilterAttribute
gets the instance of your filter from the actual service collection, which allows you to define a specific lifetime to it, whereas TypeFilterAttribute
does not use the service collection to create your object, it uses Microsoft.Extensions.DependencyInjection.ObjectFactory which is the result of CreateFactory method. (Basically it creates your object with a lot of expression trees.) TypeFilterAttribute
also allows you to pass arguments for non-service constructor parameters. Both use the service collection for any DI.
For your existing codebase you can quite simply do any of the following to achieve Dependency injection in the constructor of an attribute:
[TypeFilter(typeof(MyExistingFilterWithConstructorDI))]
[TypeFilter(typeof(MyExistingFilterWithConstructorDIAndParams), Arguments = new object[] { "first non-service param", "second non-service param" })]
[ServiceFilter(typeof(MyExistingFilterWithConstructorDI))
(you will need to register your filter into the service collection with an appropriate lifetime)
Now, as far as performance goes, if you end up using TypeFilterAttribute
, the type for your filter will be created as mentioned above, with expression trees, whereas if you simply create your own IFilterFactory
, you control that part, i.e you simply instantiate your object, and for any dependency injection needs - you use the provided IServiceProvider
as part of the CreateInstance
method for the interface.
The IsReusable
property, as part of the IFilterFactory
interface is there for you to show if you prefer the framework to use your object outside of the request scope. This, in no way guarantees that you'll ever be stuck with a single object for your filter.