构造对象时的依赖注入

时间:2012-02-13 15:53:03

标签: asp.net-mvc dependency-injection ninject

我正在为我的控制器创建一个自定义ActionResult,因为我注意到很多可以重复使用的重复代码。它看起来像这样:

 public ExtendedViewResult<T> : ActionResult
 {
      protected T Model { get; set; }
      protected IModelExtender<T> Extender { get; set; }

      public ExtendedActionResult(T model, IModelExtender<T> extender)
      {
          this.Model = model;
          this.Extender = extender;
      }
 }

 public class BaseController : Controller
 {
     public ExtendedViewResult<T> ExtendedView<T>(T model)
     {
         // I need to create the result here, but how?
         var result = new ExtendedViewResult<T>(model, ???????);

         return result;
     }
 }

我遇到的问题是我不确定如何构造我的ExtendedViewResult对象。由于接口是通用的,我想使用依赖注入来获取正确的对象,但我不知道如何做到这一点,因为我自己构建对象。

我正在使用Ninject和Ninject.MVC3,默认的Nuget包为我创建了一个Bootstrapper类,当我访问Bootstrapper.Kernel属性时,我收到以下警告:

Ninject.Web.Mvc.Bootstrapper.Kernel is obsolete. Do not use Ninject as Service Locator.

如果我不应该直接访问内核,那么如何更改代码以便我可以获得适当的具体类?

修改
这是ninject引导程序代码。我添加的唯一方法是GetInstance()

public static class NinjectMVC3 
{
    private static readonly Bootstrapper bootstrapper = new Bootstrapper();

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start() 
    {
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestModule));
        DynamicModuleUtility.RegisterModule(typeof(HttpApplicationInitializationModule));
        bootstrapper.Initialize(CreateKernel);
    }

    /// <summary>
    /// Stops the application.
    /// </summary>
    public static void Stop()
    {
        bootstrapper.ShutDown();
    }

    // I ADDED THIS CODE, EVERYTHING ELSE IS AUTO-GENERATED
    // BY THE NUGET PACKAGE
    public static T GetInstance<T>()
    {
        return bootstrapper.Kernel.Get<T>();
    }

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        RegisterServices(kernel);
        return kernel;
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
    }        
}

2 个答案:

答案 0 :(得分:1)

很抱歉这对于实际代码来说会很干 - 我没有使用ninject,但是其他DI容器都有这个解决方案,我相信ninject也会有这个构造。

问题是你正在构建对象本身。当你真正使用DI容器并关注IoC时,只要你看到关键字new应该是一个红色标志 - 并且使用容器作为服务定位器是黄色的。

那么我们如何摆脱'新',因为你需要一个新的对象?答案是让您的BaseController依赖可以创建ExtendedViewResult的工厂。在Autofac(我选择的容器)中,这就像注入Func<ExtendedViewResult>一样简单。如果Ninject没有相同的话,我会感到惊讶。事实上,它看起来像 - this ninject wiki page指向此blog post on Ninject.Extensions.Factory

这意味着您的Controller代码可能如下所示:

public class ConcreteController : BaseController
 {
     private Func<Foo,ExtendedViewResult<Foo>> _factory;
     public BaseController(Func<Foo,ExtendedViewResult<Foo>> factory)
     { 
        _factory = factory;
     }

     public ExtendedViewResult<Foo> Method(Foo model)
     {            
         var result = _factory(model);    
         return result;
     }
 }

如果你真的想要一个通用的方法在基类中进行创建,那么你可能需要从上面链接的博客文章中去显式工厂界面路径。但是,使用这种样式代码,在大多数情况下您不需要它,并且您的控制器显式声明了它们所需的依赖项。

答案 1 :(得分:0)

当您的对象想要创建其他对象时,您应该使用抽象工厂。抽象工厂本身可以注入。我在这里问了一个类似的问题:Abstract factories when using dependency injection frameworks

尽管你的工厂是通用的,但实际上并没有太大区别。