如何将命名依赖项注入控制器?
How do I inject named dependencies in to a controller?
我创建了一个配置了 Unity MVC 和 Unity Web API 的 C# ASP 项目。
我不想在依赖于它们的对象中定义 名称 依赖项 - 我试图将该配置与其他容器配置放在一起。
但我正在努力确定如何使用控制器来做到这一点?我的控制器看起来像:
namespace MyService.Controllers
{
public class HomeController : Controller
{
private ITest test;
public HomeController(ITest test)
{
this.test = test;
}
public ActionResult Index()
{
ViewBag.Title = "Home Page";
return View();
}
}
}
我目前对容器配置的尝试如下:
container.RegisterType<ITest>("bar",
new InjectionFactory(c => new TestImpl1()));
container.RegisterType<ITest>("foo",
new InjectionFactory(c => new TestImpl2()));
container.RegisterType<HomeController>("Home",
new InjectionFactory(c => new HomeController(
c.Resolve<ITest>("foo")
)));
但我最终遇到了这个例外:
The current type, MyService.App_Start.ITest, is an interface and cannot be constructed. Are you missing a type mapping?
这对我来说意味着它没有使用容器来获取注册的 HomeController。我不确定如何正确连接它?
解决方案
采用公认的答案,对我有用的确切解决方案是注册这个控制器工厂;
public class UnityControllerFactory : DefaultControllerFactory
{
private readonly IUnityContainer _container;
public UnityControllerFactory(IUnityContainer container)
{
_container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return base.GetControllerInstance(requestContext, null);
}
return _container.Resolve(controllerType) as IController;
}
}
在 Start() 中使用这个来实际注册它,当然:
ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container));
MVC 中的控制器是由控制器工厂创建的。如果你想要用户依赖注入,你必须挂钩到这个控制器工厂并进行你的覆盖,这将使用统一。
public class MgsMvcControllerFactory : DefaultControllerFactory {
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) {
// our controller instance will have dependency injection working
if (!ServiceLocator.IoC.IsServiceRegistered(controllerType, controllerType.FullName)) {
ServiceLocator.IoC.RegisterType(controllerType, controllerType.FullName, new ContainerControlledLifetimeManager())
}
return ServiceLocator.IoC.Resolve<IController>(controllerType.FullName);
}
}
在global.asax.cs中:
protected void Application_Start() {
// initialization of unity container
ServiceLocator.IoC = ...;
var factory = new MgsMvcControllerFactory()
ControllerBuilder.Current.SetControllerFactory(factory);
}
另一种选择(恕我直言)是创建基础 Controller
- 我们称它为 DIController
,它将在构造函数中调用 BuildUp()
并从此 [= 继承其余控制器13=]。不用说,您必须将基于构造函数的注入重写为方法或基于 属性 的注入。
我创建了一个配置了 Unity MVC 和 Unity Web API 的 C# ASP 项目。
我不想在依赖于它们的对象中定义 名称 依赖项 - 我试图将该配置与其他容器配置放在一起。
但我正在努力确定如何使用控制器来做到这一点?我的控制器看起来像:
namespace MyService.Controllers
{
public class HomeController : Controller
{
private ITest test;
public HomeController(ITest test)
{
this.test = test;
}
public ActionResult Index()
{
ViewBag.Title = "Home Page";
return View();
}
}
}
我目前对容器配置的尝试如下:
container.RegisterType<ITest>("bar",
new InjectionFactory(c => new TestImpl1()));
container.RegisterType<ITest>("foo",
new InjectionFactory(c => new TestImpl2()));
container.RegisterType<HomeController>("Home",
new InjectionFactory(c => new HomeController(
c.Resolve<ITest>("foo")
)));
但我最终遇到了这个例外:
The current type, MyService.App_Start.ITest, is an interface and cannot be constructed. Are you missing a type mapping?
这对我来说意味着它没有使用容器来获取注册的 HomeController。我不确定如何正确连接它?
解决方案
采用公认的答案,对我有用的确切解决方案是注册这个控制器工厂;
public class UnityControllerFactory : DefaultControllerFactory
{
private readonly IUnityContainer _container;
public UnityControllerFactory(IUnityContainer container)
{
_container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return base.GetControllerInstance(requestContext, null);
}
return _container.Resolve(controllerType) as IController;
}
}
在 Start() 中使用这个来实际注册它,当然:
ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container));
MVC 中的控制器是由控制器工厂创建的。如果你想要用户依赖注入,你必须挂钩到这个控制器工厂并进行你的覆盖,这将使用统一。
public class MgsMvcControllerFactory : DefaultControllerFactory {
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) {
// our controller instance will have dependency injection working
if (!ServiceLocator.IoC.IsServiceRegistered(controllerType, controllerType.FullName)) {
ServiceLocator.IoC.RegisterType(controllerType, controllerType.FullName, new ContainerControlledLifetimeManager())
}
return ServiceLocator.IoC.Resolve<IController>(controllerType.FullName);
}
}
在global.asax.cs中:
protected void Application_Start() {
// initialization of unity container
ServiceLocator.IoC = ...;
var factory = new MgsMvcControllerFactory()
ControllerBuilder.Current.SetControllerFactory(factory);
}
另一种选择(恕我直言)是创建基础 Controller
- 我们称它为 DIController
,它将在构造函数中调用 BuildUp()
并从此 [= 继承其余控制器13=]。不用说,您必须将基于构造函数的注入重写为方法或基于 属性 的注入。