如何将命名依赖项注入控制器?

时间:2015-03-05 12:21:55

标签: c# asp.net asp.net-mvc asp.net-web-api unity-container

我已经创建了一个配置了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));

1 个答案:

答案 0 :(得分:2)

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()并从此{{1}继承其余控制器}。毋庸置疑,您必须将基于构造函数的注入重写为基于方法或属性的注入。