Как правильно внедрить IDBContextFactory в контроллер ввода IDomainFactory с помощью Ninject MVC3? - PullRequest
2 голосов
/ 22 февраля 2012

Предварительные сведения

  1. Я использую Ninject.MVC3 2.2.2.0 Nuget Package для внедрения в мой контроллер реализации интерфейса IDomain, который разделяет мою бизнес-логику (BL) с использованием подхода Factory.
  2. Я регистрирую свои Ninject-модули в предварительно настроенном NinjectMVC3.cs , используя:

    private static void RegisterServices(IKernel kernel)
    {
        var modules = new INinjectModule[]
        {
            new DomainBLModule(),
            new ADOModule()
        };
        kernel.Load(modules);
    }
    
  3. Я пытаюсь избежатьроковое проклятие дьявольского Service Locator anti-pattern.

Класс домена использует 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();
    }
}

На этом этапе я могу внедрить реализацию IDomainBLFactory в мой контроллер с помощью Ninject Constructor Injection без каких-либо проблем:

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

Теперь моя центральная проблема.

В ДоменеРеализация BL, я добавлю зависимость к определенному DBContext, в этом случае ADO DBContext из Entity Framework, снова, используя IDBContextFactory:

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 .Но я не знаю, что добавить в вызов для Factory CreateNew () в IDBContextFactory.Для ясности:

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

    В этом Полезном посте , наш уникальный верный друг Ремо Глур описывает в комментарии возможное решение для меня, цитируя: " Создайте интерфейс с методом CreateSomething, который берет все необходимое для создания экземпляра и возвращает его. Затем в вашей конфигурации вы реализуете этот интерфейс и добавляете IResolutionRoot в его конструктор и используете это instace для получения требуемого объекта . "

    Вопросы : Как правильно реализовать это, используя Ninject.MVC3 и мой скромный подход к классу доменов?Как разрешить IResolutionRoot без наказания за ретрансляцию в анти-шаблоне Service Locator?

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

    Вопрос: Есть ли большая ошибка в моем пониманииФабричный подход для внедрения сопряженных реализаций и с использованием доменного подхода для разделения бизнес-логики?В случае, если я ошибаюсь, какой набор шаблонов я должен реализовать с уверенностью?

    Я видел перед действительно большим количеством статей и блогов, которые не задают этот важный вопрос открыто и ясно.


RemoGloor представляет Ninject.Extensions.Factory для Ninject 3.0.0 RC на сайте www.planetgeek.ch/2011/12/31/ninject-extensions-factory-introduction.

Вопрос: Будет ли работать это расширение в сочетании с Ninject.MVC3 для обычного porpouse ?.В таком случае это должна быть моя надежда на ближайшее будущее.

Спасибо всем заранее за ваше руководство и помните, что мы ценим вашу любезную помощь.Я думаю, что многие найдут этот сценарий полезным.

Ответы [ 2 ]

1 голос
/ 16 мая 2012

Вот реализация универсального 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)
  }

А в вашем Домене BL

  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)
  }
1 голос
/ 22 февраля 2012

Я действительно не понимаю цель ваших фабрик. Обычно у вас есть ровно один экземпляр ObjectContext для одного запроса. Это означает, что вам не нужна фабрика, и вы можете просто связать myADOEntities в области запросов и вставить ее в DomainBL, не добавляя фабрики:

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

И да, заводские и MVC-расширения работают вместе.

...