How to dynamically inject service into asp.net web api controller based on http request parameter using Unity

I use Unity to insert a service instance into the constructor of my ASP.NET API.

In the code below, I want to add another implementation of IAuthenticationService based on the http request made.

Is it possible?

public class AuthenticateController : ApiController { public AuthenticateController(IAuthenticationService authenticationService) { } 
+5
source share
1 answer

The short answer is that this is possible, but I would not recommend it, since for an IoC container I would have to use HttpContext.Current statically for this. What I recommend looks like this:

 public interface IProvideAuthenticationService { IAuthenticationService GetService(string requestMethod); } public class AuthenticationServiceProvider : IProvideAuthenticationService { public IAuthenticationService GetService(string requestMethod) { switch (requestMethod) { case "GET": return new HttpGetAuthenticationService(); case "POST": return new HttpPostAuthenticationService(); default: throw new NotSupportedException(string.Format( "Cannot find AuthenticationService for requestMethod '{0}'", requestMethod)); } } } public class AuthenticateController : ApiController { private readonly IProvideAuthenticationService _authenticationServiceProvider; public AuthenticateController(IProvideAuthenticationService authenticationServiceProvider) { _authenticationServiceProvider = authenticationServiceProvider; } [HttpGet] public ActionResult Get() { IAuthenticationService authService = _authenticationServiceProvider.GetService(HttpContext.Request.HttpMethod); } [HttpPost] public ActionResult Post() { IAuthenticationService authService = _authenticationServiceProvider.GetService(HttpContext.Request.HttpMethod); } } 

The argument of the provider provider does not have to be a string; it can be an HttpContextBase or some other object that has the data necessary to decide which implementation should be returned. Then you register the supplier with unity, and the designer enters it into the controller (s). Finally, in the steps you use the provider to get the correct authentication service implementation.

If you really wanted to avoid the provider / factory pattern, I honestly don't know how it will look in Unity. But in SimpleInjector (another IoC library that basically does the same things as Unity), it will look something like this:

 container.Register<IAuthenticationService>(() => { string requestMethod = HttpContext.Current.Request.HttpMethod; switch (requestMethod) { case "GET": return new HttpGetAuthenticationService(); case "POST": return new HttpPostAuthenticationService(); default: throw new NotSupportedException(string.Format("Cannot find AuthenticationService for requestMethod '{0}'", requestMethod)); } }); 

Although the above should work (and there should be a similar way to do this with Unity), it can only do this with the static HttpContext.Current object. I usually don’t like this approach because it hides knowledge at the root of the composition and effectively does the same thing as the provider. But this is only my opinion, you can also choose.

But what if the services need the injections themselves?

During root composition:

 container.Register<HttpGetAuthenticationService>(); container.Register<HttpPostAuthenticationService>(); 

Provider Execution:

 public class AuthenticationServiceProvider : IProvideAuthenticationService { private readonly Container _container; public AuthenticationServiceProvider(Container container) { _container = container; } public IAuthenticationService GetService(string requestMethod) { switch (requestMethod) { case "GET": return _container.GetInstance<HttpGetAuthenticationService>(); case "POST": return _container.GetInstance<HttpPostAuthenticationService>(); default: throw new NotSupportedException(string.Format( "Cannot find AuthenticationService for requestMethod '{0}'", requestMethod)); } } } 

... again, this is not code for Unity, but I would expect Unity to do the same, even if the API is different. I agree with @Maarten that such things can go either at the root of the composition or at the application provider. I just prefer the latter over the former, probably because it seems less magical to me.

+4
source

All Articles