Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How would I pass a Web API Request through Dependency Injection?

I am having a Web API application in which the controller has Services/Repositories etc. injected into it through Dependency Injection (Unity). Let's assume that I have an IStuffService that needs the IPrincipal of the current request (or a wrapper around it).

The problem with Web API seems to be that the only reliable source of the current Request/User is the Request property on the instance of the ApiController. Anything static (be it HttpContext.Current, CallContext.Get/SetData or Thread.Get/SetData) is not guaranteed to be on the same thread due to the sync nature of Web API.

How do I reliably ensure that Request-specific context is passed through dependencies, and more importantly, that the operation retains the correct IPrincipal all the way through the operation?

Two options:

  1. Every method that needs an IPrincipal has it as an argument to the method - that is the most reliable way, but it also requires me to have that thing in every method signature
  2. Inject the IPrincipal into the ctor of the Service, spinning up a new insance of the object graph on every request, using a DependencyOverride in Unity: container.Resolve(opType, new DependencyOverride(typeof(IPrincipal), principal))

Option 2 means that my method signatures are clean, but it also means I need to make sure all dependencies are using the TransientLifetimeManager, not a Singleton or even Per-Thread one.

Is there a better solution than I'm not seeing?

like image 714
Michael Stum Avatar asked Jun 18 '14 21:06

Michael Stum


People also ask

What is dependency injection in Web API?

“ - In software development, dependency injection is a technique where one object supplies the needs, or dependencies, of another object.

Which API is used by Spring framework for dependency injection?

What is Dependency Injection: Dependency Injection is the main functionality provided by Spring IOC(Inversion of Control). The Spring-Core module is responsible for injecting dependencies through either Constructor or Setter methods.

Which is the right way to inject the dependency?

Constructor injection should be the main way that you do dependency injection. It's simple: A class needs something and thus asks for it before it can even be constructed. By using the guard pattern, you can use the class with confidence, knowing that the field variable storing that dependency will be a valid instance.

How can we inject the dependency into the controller?

ASP.NET Core injects objects of dependency classes through constructor or method by using built-in IoC container. The built-in container is represented by IServiceProvider implementation that supports constructor injection by default. The types (classes) managed by built-in IoC container are called services.


1 Answers

From the comments:

@MichaelStum, I believe HttpContext.User should be flowed correctly across async/await (within the same HTTP request). Is it not for you? – Noseratio 17 hours ago

@Noseratio See the other answers - in .net 4.0, it's bound to the current thread and was not properly maintained. It seems that in 4.5, this might be fixed. That said, HttpContext.Current is still not that appropriate in Web API because on self-hosted ones there is no HttpContext.Current.

AFAIK, there's no proper support for async/await in ASP.NET 4.0 anyway (you probably can use Microsoft.Bcl.Async for the language support, but there is no ASP.NET runtime support, so you'd have to resort to AsyncManager to implement the TAP pattern).

That said, I'm 99% sure Thread.CurrentPrincipal would still be correctly flowed across await continuations in ASP.NET 4.0. That's because it gets flowed as a part of ExecutionContext flow, rather than by synchronization context. As to HtttContext.Current.User, I'm not sure if it would flow correctly in ASP.NET 4.0 (although it certainly does in ASP.NET 4.5).

I've re-read your question, but could find an explicit complaint about Thread.CurrentPrincipal not being correctly flowed. Are you experiencing this issue in existing code (if so, it probably would be a bug in ASP.NET)?

Here's a list of related questions, answered with some great insights by Stephen Cleary:

  • Understanding context in C# 5 async/await

  • Why is an "await Task.Yield()" required for Thread.CurrentPrincipal to flow correctly?

  • Using ASP.NET Web API, my ExecutionContext isn't flowing in async actions

This blog post by Scott Hanselman is also related, although he speaks about WebForms:

  • System.Threading.Thread.CurrentPrincipal vs. System.Web.HttpContext.Current.User or why FormsAuthentication can be subtle

If you're concerned about self-hosting scenarios, I believe Thread.CurrentPrincipal will still be flowed correctly there (once having been set to a correct identity). If you want to flow any other properties (besides those which get automatically flowed with ExecutionContext), you can roll out your own synchronization context. Another option (not so nice, IMO) is to use custom awaiters.

Finally, if you face a situation where you actually require thread affinity across await continuation (much like in a client side UI app), you have such option, too (again, using a custom synchronization context):

  • How to use non-thread-safe async/await APIs and patterns with ASP.NET Web API?
like image 68
noseratio Avatar answered Oct 03 '22 08:10

noseratio