简体   繁体   中英

How do I inject named dependencies in to a controller?

I've created a C# ASP project with Unity MVC and Unity Web API configured.

I don't want to define the names of dependencies in objects which depend on them - I'm trying to keep that configuration alongside the other container configuration.

But I'm struggling to determine how to do that with controllers? My controller looks like:

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();
        }
    }
}

And my current attempt at container configuration looks like:

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")
    )));

But I end up with this exception:

The current type, MyService.App_Start.ITest, is an interface and cannot be constructed. Are you missing a type mapping?

Which implies to me that it's not using the container to get the registered HomeController. I'm not sure how to wire this up correctly?

Solution

Taking the accepted answer, the exact solution which worked for me is registering this controller factory;

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;
    }
}

With this in Start() to actually register it, of course:

ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container));

Controllers in MVC are created by controller factory. If you want to user dependency injection, you have to hook to this controller factory and make your override that will make use of unity.

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);
  }
}

And in global.asax.cs:

protected void Application_Start() {
  // initialization of unity container
  ServiceLocator.IoC = ...; 
  var factory = new MgsMvcControllerFactory()
  ControllerBuilder.Current.SetControllerFactory(factory);
}

Alternative (lot less cool IMHO) is creation of base Controller - let's call it DIController that will call BuildUp() in constructor and inherit rest of the controllers from this DIController . Needless to say you'll have to rewrite constructor based injection to method or property based injection.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM