我正在使用Unity将服务实例注入到我的ASP.NET Web API控制器的构造函数中。
在下面的代码中,我想根据发出的http请求注入不同的IAuthenticationService实现。
这可能吗?
public class AuthenticateController : ApiController
{
public AuthenticateController(IAuthenticationService authenticationService)
{
}
答案 0 :(得分:4)
简短的回答是它是可能的,但我不推荐它,因为IoC容器必须静态地使用HttpContext.Current
来完成它。我推荐的是更像这样的模式:
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);
}
}
提供程序方法arg不必是字符串,它可以是HttpContextBase
或任何具有您需要的数据的对象来决定返回哪个实现。然后使用unity注册提供程序,构造函数将其注入控制器。最后,在操作中,您使用提供程序来获取正确的身份验证服务实现。
如果你真的想避开提供商/工厂模式,老实说我不知道Unity中会是什么样子。但是在SimpleInjector(另一个基本上与Unity相同的IoC库)中,它看起来像这样:
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));
}
});
虽然上面应该有效(并且应该与Unity一样),但它只能通过使用静态HttpContext.Current
对象来实现。我通常不喜欢这种方法,因为它隐藏了组合根中的知识,并且有效地做了与提供者相同的事情。但这只是我的观点,你可以自由选择。
根组合期间:
container.Register<HttpGetAuthenticationService>();
container.Register<HttpPostAuthenticationService>();
提供商实施:
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));
}
}
}
...再次这不是Unity的代码,但我希望Unity可以做同样的事情,即使API不同。我同意@Maarten这种事情可以在组合根或应用程序级提供程序中进行。我倾向于选择后者而不是前者,可能是因为它对我来说似乎不太“神奇”。