如何使用Ninject MVC3将IDBContextFactory正确注入控制器的注入IDomainFactory?

时间:2012-02-22 13:40:27

标签: dependency-injection ninject ninject-2 ninject.web.mvc ninject-extensions

预赛

  1. 我正在使用Ninject.MVC3 2.2.2.0 Nuget Package向我的控制器中注入一个IDomain接口的实现,该接口使用Factory方法分离我的业务逻辑(BL)。
  2. 我正在预先配置的 NinjectMVC3.cs 中注册我的Ninject模块:

    private static void RegisterServices(IKernel kernel)
    {
        var modules = new INinjectModule[]
        {
            new DomainBLModule(),
            new ADOModule()
        };
        kernel.Load(modules);
    }
    
  3. 我正在努力避免恶意服务定位器反模式的致命诅咒。

  4. Domain Class使用DBContext,我试图通过IDBContext注入接口实现,具体情况如下:

    IDomainBLFactory

    public interface IDomainBLFactory
    {
        DomainBL CreateNew();
    }
    

    DomainBLFactory

    public class DomainBLFactory : IDomainBLFactory
    {
        public DomainBL CreateNew()
        {            
            return new DomainBL();
        }
    }
    

    在控制器的命名空间中:

    public class DomainBLModule : NinjectModule
    {
        public override void Load()
        {
            Bind<IDomainBLFactory>().To<DomainBLFactory>().InRequestScope();
        }
    }
    

    此时我可以使用Ninject Constructor Injection将IDomainBLFactory实现注入到我的控制器中而没有任何问题:

    public class MyController : Controller
    {
        private readonly IDomainBLFactory DomainBLFactory;
        // Default Injected Constructor
        public MyController(IDomainBLFactory DomainBLFactory)
        {
            this.DomainBLFactory = DomainBLFactory;
        }
        ... (use the Domain for performing tasks/commands with the Database Context)
    }
    

    现在是我的核心问题。

    在DomainBL实现中,我将使用IDBContextFactory将依赖项注入特定的DBContext,在本例中是来自Entity Framework的ADO DBContext:

    IDbDataContextFactory

    public interface IDbDataContextFactory
    {
        myADOEntities CreateNew();
    }
    

    DbDataContextFactory

    public class DbDataContextFactory : IDbDataContextFactory
    {
        public myADOEntities CreateNew()        
        {
            return new myADOEntities ();
        }
    }
    

    ADOModule

    public class ADOModule : NinjectModule
    {
        public override void Load()
        {
            Bind<IDbDataContextFactory>().To<DbDataContextFactory>().InRequestScope();
        }
    }
    

    现在在DomainBL实现中我遇到了为DBContext对象工厂注入必要接口的问题:

    public class DomainBL
    {
      private readonly IDbDataContextFactory contextFactory;
      **** OPS, i tried to understand about 10+ Stackoverflow articles ***
      ...
    }
    

    我尝试了什么?

    1. 使用构造函数Injection 。但我不知道在IDBContextFactory中调用Factory CreateNew()时要注入什么。为清楚起见:

      public class DomainBLFactory: IDomainBLFactory        
      {
          // Here the constructor requires one argument for passing the factory impl.
          public DomainBL CreateNew()
          {
              return new DomainBL(?????)  // I need a IDBContextFactory impl to resolve.
              //It's not like in the MVC Controller where injection takes place internally
              //for the controller constructor. I'm outside a controller
          }
      }
      

      在这个Useful Post中,我们独特的真正朋友 Remo Gloor 在评论中为我描述了一个可能的解决方案,引用:“创建一个具有CreateSomething方法的接口创建实例所需的一切,让它返回实例。然后在配置中实现此接口并将IResolutionRoot添加到其构造函数中,并使用此实例获取所需对象。“

      问题:如何使用Ninject.MVC3和我适度的Domain Class方法以正确的方式实现这一点?如何解决IResolutionRoot而不会因服务定位器反模式中继而受到惩罚?

    2. 为IDBContexFactory使用属性注入。在学习和阅读所有矛盾的观点以及对它的理论解释的过程中,我可以推断出它不是为我的DBContexFactory类代码进行注入的正确方法。没关系。它无论如何都不起作用。

      public class DomainBL
      {
      
        [Inject]
        public IDbDataContextFactory contextFactory
        {
            get;
            set;
        }
        //Doesn't works, contextFactory is null with or without parameterless constructor
        .... (methods that uses contextFactory.CreateNew()....
      
      }
      

      问题:我错过了什么?即使这种做法是错误的,财产也不会注入。

    3. 被诅咒。使用DependencyResolver并与耻辱一起生活。这有效,我将继续采用这种方法,直到找到适当的解决方案。这真是令人沮丧,因为我过去10天努力理解并做正确的事情缺乏知识。

      public class DomainBL
      {
        private readonly IDbDataContextFactory contextFactory;
        this.contextFactory = DependencyResolver.Current.GetService<IDbDataContextFactory>();
        //So sweet, it works.. but i'm a sinner.
      
      }
      

      问题:我对注入接口实现的工厂方法的理解是否存在重大错误,而using a Domain Driven Approach用于拆分业务逻辑?如果我错了,我应该自信地实施哪些模式?

      我之前看过很多文章和博客,并没有明确地提出这个重要问题。


    4. Remo Gloor 在www.planetgeek.ch/2011/12/31/ninject-extensions-factory-introduction中介绍了Ninject 3.0.0 RC的Ninject.Extensions.Factory。

      问题:此扩展程序是否与Ninject.MVC3一起用于普通porpouse?在这种情况下,它应该是我对不久的将来的希望。

      提前感谢您的指导,并记住我们感谢您的帮助。我想很多人会发现这种情况也很有用。

2 个答案:

答案 0 :(得分:1)

我真的没有达到你工厂的目的。通常,您只有一个ObjectContext实例用于一个请求。这意味着您不需要工厂,只需在请求范围中绑定myADOEntities并将其注入DomainBL而无需添加工厂:

Bind<myADOEntities>().ToSelf().InRequestScope();
Bind<DomainBL>().ToSelf().InRequestScope();

是的,工厂和mvc extrensions一起工作。

答案 1 :(得分:1)

这是一个通用IFactory的实现,可以在不诉诸ServiceLocator反模式的情况下解决问题。

首先定义一个漂亮的通用工厂接口

  public interface IFactory<T>
  {
    T CreateNew();
  }

并定义使用ninject内核创建所请求对象的实现

  class NinjectFactory<T> : IFactory<T>
  {
    private IKernel Kernel;

    public NinjectFactory( IKernel Kernel )
    {
      this.Kernel = Kernel;
    }

    public T CreateNew()
    {
      return Kernel.Get<T>();
    }
  }

使用以下

绑定到您的工厂
  private static void RegisterServices(IKernel kernel)
  {
    kernel.Bind<myADOEntities>().ToSelf();
    kernel.Bind<DomainBL>().ToSelf();
    kernel.Bind(typeof(IFactory<>)).To(typeof(NinjectFactory<>));
  }        

您现在可以在控制器中执行以下操作。

  public class MyController : Controller
  {
    private readonly IFactory<DomainBL> DomainBLFactory;

    public MyController( IFactory<DomainBL> DomainBLFactory )
    {
      this.DomainBLFactory = DomainBLFactory;
    }

    // ... (use the Domain for performing tasks/commands with the Database Context)
  }

在你的DomainBL中

  public class DomainBL
  {
    IFactory<myADOEntities> EntitiesFactory;

    public DomainBL( IFactory<myADOEntities> EntitiesFactory )
    {
      this.EntitiesFactory = EntitiesFactory;
    }

    // ... (use the Entities factory whenever you need to create a Domain Context)
  }