Injecting into attributes?

Mar 2, 2015 at 2:05 PM
We're using SimpleInjector in a WebAPI webservice.

We have a couple of custom attributes that need access to objects that we're controlling access to via SimpleInjector. We have a UserContext object, for example, that tracks information about the currently-logged-in user. We have it registered with a WebApiRequestLifestyle, and inject it into most of our Controller Actions. We need to inject that same object into our custom authentication attribute, but we didn't see a clean mechanism for doing so.

What we've done is to create a static reference to the SimpleInjector container. We set that reference in our SimpleInjector Register() function (where we register all of our base types with SimpleInjector on startup). Then we get references to the objects we need by calling container.GetInstance().

This is all working fine, but I don't like it. There's a smell about it.

I'm wondering if anyone is aware of a cleaner mechanism for injecting objects into a custom attribute?
Coordinator
Mar 2, 2015 at 2:18 PM
A thorough discussion about how to handle this is given in the article Dependency Injection in Attributes: don’t do it!. You'll find exactly the information you are looking for in that article.
Mar 2, 2015 at 4:28 PM
I'm not sure that the issues raised in that article are relevant to our use.
Coordinator
Mar 2, 2015 at 4:54 PM
Hi jdege,

Dependency Injection into Web API attributes is simply not possible, except if you're absolutely sure that all the dependencies of all your attributes are -and always will be- singletons. This is because Web API caches attributes. Since you are talking about some context object that is registered with a per-request lifestyle, dependency injection is not an option for you, since the attribute will keep the dependency alive for the duration of the application (a defect known as captive dependency) which will most likely cause concurrency bugs.

You have two possible options: either you move to passive attributes (i.e. attributes without logic) as explained in the referenced article, or you fall back at using the Service Locator pattern (i.e. calling the container or an abstraction that represents the container) in your attribute's OnActionExecutXXX methods (which is the method you are already using). Because of the many downsides of the Service Locator pattern, my advice is to go for passive attributes.
Marked as answer by jdege on 3/2/2015 at 2:11 PM
Mar 2, 2015 at 7:53 PM
What we have is simple, in concept.
  1. We expect our webservices to be called with an access token in a custom header. We have a custom authorization attribute that looks for that header and determines whether or not the call is authorized. Currently, all we're doing is using the token as a key in the http runtime cache. If the key doesn't exist, you're not let in.
  2. We have a class called UserContext, that contains information about the currently-logged-in user. We have it registered as a per-web-request object, in Simple Injector, and we inject it into our controller actions - so each action is handed the same UserContext object.
  3. At login, when we create the access token, we create the UserContext and store it in the http runtime cache, using the access token as the key.
So, we either need to have every controller action retrieve the UserContext from the http runtime cache, and populate the per-web-request UserContext object, or we have the authorization attribute - which has to pull the UserContext from the http runtime cache anyway, to determine whether to allow access - populate the per-web-request UserContext object.

It makes for about eight lines of code that needs to exist in one place, instead of in hundreds. Which makes it worth a bit of code smell.

But it sounds as if what we are doing - ServiceLocator pattern - is as good a way of handling this as we're going to find.
Coordinator
Mar 3, 2015 at 9:59 AM
Note that the Web API integration documentation for Simple Injector discusses this as well.