2015-05-29 4 views
2

Я пишу небольшую структуру, которая выполняла несколько задач. Некоторые задачи требуют определенных свойств, которые вводятся через Ninject.Является ли хорошей практикой передавать ядро ​​Ninject?

Давайте предположим, что у меня есть следующий конструктор в своем базовом классе, который представляет собой единственную задачу:

protected DDPSchedulerTask(ILogger logger, List<string> platforms, IBackOfficeDataStore backOfficeDataStore, ICommonDataStore commonDataStore) 
{ 
    _logger = logger; 
    _platforms = platforms; 
    _backOfficeDataStore = backOfficeDataStore; 
    _commonDataStore = commonDataStore; 
} 

Эти свойства необходимы для всех задач, так что я впрыскивать их с помощью Ninject со следующим модулем Ninject.

public class DDPDependencyInjectionBindingConfiguration : NinjectModule 
{ 
    #region NinjectModule Members 

    /// <summary> 
    ///  Loads the module into the kernel. 
    /// </summary> 
    public override void Load() 
    { 
     Bind<Scheduler>().ToSelf(); // Make sure that the 'Scheduler' is resolved to itself. 
     Bind<ILogger>().ToMethod(context => LogFactory.Create()); // Make sure that an instance of an ILogger is created through the LogFactory. 

     // Straightforward binding. 
     Bind<ICommonDataStore>().To<Common>(); 
     Bind<IBackOfficeDataStore>().To<BtDbInteract>(); 
     Bind<IDirectoryResolver>().To<Demo>(); 
    } 

    #endregion 
} 

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

var schedulerInstance = kernel.Get<Scheduler>(); 

Теперь мой планировщика есть метод, который добавляет задачи в список, так что не с помощью Ninject:

var tasksList = new List<DDPSchedulerTask> 
{ 
    new AWNFileGeneratorTask(_logger, availablePlatforms, _backOfficeDataStore, _commonDataStore) 
}; 

Затем все эти задачи выполняются. Теперь некоторые из этих задач требуют дополнительных зависимостей, которые я бы хотел разрешить через Ninject, но как мне это сделать?

Внутри задачи я создал свойство с атрибутом Inject, но объект остается нулями.

[Inject] 
private IDirectoryResolver directoryResolver { get; set; } 

У кого-нибудь есть идея, как это можно решить?

Я могу передать ядро ​​в разные задачи, но что-то говорит мне, что это неправильный подход.

С уважением

ответ

3

В таких случаях я обычно использую шаблон Factory. В планировщике вы можете иметь фабрику задач как зависимость. Эта фабрика также может иметь несколько методов для создания различных типов задач.

class DDPSchedulerTaskFactory : IDDPSchedulerTaskFactory 
{ 
    DDPSchedulerTaskFactory(ILogger logger, List<string> platforms, IBackOfficeDataStore backOfficeDataStore, ICommonDataStore commonDataStore) 
    { 
     _logger = logger; 
     _platforms = platforms; 
     _backOfficeDataStore = backOfficeDataStore; 
     _commonDataStore = commonDataStore; 
    } 

    public IDDPSchedulerTask CreateNormal(){ 
     return new DDPSchedulerTask(
      _logger, 
      _platforms, 
      _backOfficeDataStore, 
      _commonDataStore); 
    } 

    public IDDPSchedulerTask CreateSpecial(someAdditionalParameter){ 
     return new AnotherDDPSchedulerTask(
      _logger, 
      _platforms, 
      _backOfficeDataStore, 
      _commonDataStore, 
      someAdditionalParameter); 
    } 

    public IDDPSchedulerTask CreateTaskWithDifferentDependenties(yetAnotherParameter){ 
     return new AnotherDDPSchedulerTask(
      _logger, 
      _platforms, 
      yetAnotherParameter); 
    } 
} 

чем в вашем планировщиком вы можете добавлять задачи так:

class Scheduler{ 
    IDDPSchedulerTaskFactory _taskFactory; 
    public Scheduler(IDDPSchedulerTaskFactory taskFactory){ 
     _taskFactory = taskFactory; // factory gets all the needed dependencies for all tasks from DI 
    } 
    ... 

    public void ConfigureTasks(){ 
     _tasks.Add(_taskFactory.CreateNormal()); 
     _tasks.Add(_taskFactory.CreateSpecial("Some important message")); 
     _tasks.Add(_taskFactory.CreateTaskWithDifferentDependenties(123)); 
    } 
} 
+0

Хорошо, но что-то в вашем коде не правильно. В вашем методе создания возвращаемый тип устанавливается в 'DDPSchedulerTask', но вы возвращаете' DDPSchedulerTaskFactory'. Кроме того, можете ли вы объяснить немного больше своего решения?Откуда мне следует вызвать метод create, потому что я хочу, чтобы дополнительные свойства также были введены Unity. – Complexity

+0

@Complexity yep, только что скорректировал его – gisek

+0

Спасибо за исправление. Вы не возражаете, показывая мне, откуда мне нужно позвонить на эту фабрику, потому что я хотел бы продолжать использовать Ninject для обеспечения Injection Dependency. Я не вижу клей для Ninject здесь. Мне все равно нужно передать «someAdditionalParameters», где я хочу, чтобы ядро ​​Ninject разрешило это. – Complexity

4

Вы должны воспользоваться Ninject.Extensions.Factory.

Просто создайте интерфейс, который представляет ваши задачи на заводе. Затем передайте информацию в Ninject, которая является фабрикой. И он создаст для вас полные реализации этого интерфейса.

using System; 
using System.Collections.Generic; 
using Ninject; 
using Ninject.Extensions.Factory; 

internal class Program 
{ 
    public static void Main(string[] args) 
    { 
     IKernel ninjectKernel = new StandardKernel(); 

     ninjectKernel.Bind<DDPSchedulerTask>().ToSelf(); 
     ninjectKernel.Bind<AWNFileGeneratorTask>().ToSelf(); 
     ninjectKernel.Bind<IDirectoryResolver>().To<DirectoryResolver>(); 
     ninjectKernel.Bind<ITaskFactory>().ToFactory(); 

     var mainTask = ninjectKernel.Get<DDPSchedulerTask>(); 
     mainTask.CreateDbSchedulerTask(); 
     mainTask.CreateAwnFileTask(); 

     Console.ReadLine(); 
    } 
} 

public interface ITaskFactory 
{ 
    TTask CreateTask<TTask>() where TTask : DDPSchedulerTask; 
} 

public class DDPSchedulerTask 
{ 
    private readonly ITaskFactory _tasksFactory; 
    private readonly List<DDPSchedulerTask> _tasksList; 

    public DDPSchedulerTask(ITaskFactory tasksFactory) 
    { 
     _tasksFactory = tasksFactory; 

     _tasksList = new List<DDPSchedulerTask>(); 
    } 

    public void CreateAwnFileTask() 
    { 
     var task = _tasksFactory.CreateTask<AWNFileGeneratorTask>(); 
     _tasksList.Add(task); 
    } 

    public void CreateDbSchedulerTask() 
    { 
     var task = _tasksFactory.CreateTask<DDPSchedulerTask>(); 
     _tasksList.Add(task); 
    } 
} 

public class AWNFileGeneratorTask : DDPSchedulerTask 
{ 
    [Inject] 
    public IDirectoryResolver DirectoryResolver { get; set; } 

    public AWNFileGeneratorTask(ITaskFactory tasksFactory) 
     : base(tasksFactory) 
    { 
    } 
} 

public interface IDirectoryResolver 
{ 
} 

public class DirectoryResolver : IDirectoryResolver 
{ 
} 

@gisek Как отмечалось инъекции зависимостей Giseke через свойство не является лучшим решением. В этом примере вы также можете использовать инъекцию конструктора.

public class AWNFileGeneratorTask : DDPSchedulerTask 
{ 
    private IDirectoryResolver _directoryResolver; 

    public AWNFileGeneratorTask(ITaskFactory tasksFactory, IDirectoryResolver directoryResolver) 
     : base(tasksFactory) 
    { 
     _directoryResolver = directoryResolver; 
    } 
} 

Дополнительные PARAMS инъекции:

public interface ITaskFactory 
{ 
    DDPSchedulerTask CreateDDPSchedulerTask(); 
    AWNFileGeneratorTask CreateAWNFileGeneratorTask(string extraParam); 
} 

public class AWNFileGeneratorTask : DDPSchedulerTask 
{ 
    private IDirectoryResolver _directoryResolver; 
    private string _extraParam; 

    public AWNFileGeneratorTask(ITaskFactory tasksFactory, IDirectoryResolver directoryResolver, 
     string extraParam) 
     : base(tasksFactory) 
    { 
     _extraParam = extraParam; 
     _directoryResolver = directoryResolver; 
    } 
} 

public void CreateAwnFileTask() 
{ 
    var task = _tasksFactory.CreateAWNFileGeneratorTask("extra"); 
    _tasksList.Add(task); 
} 
+0

Этот способ, однако, вы привязаны к Ninject - нет возможности легко заменить контейнер IOC. (Говоря об атрибуте Inject) – gisek

+0

Нет никакой проблемы при вводе IDirectoryResolver конструктором. Он также должен работать. Например: public AWNFileGeneratorTask (ITaskFactory tasksFactory, IDirectoryResolver directoryResolver): base (tasksFactory) –

+0

Ok. А как насчет передачи дополнительных параметров (не зависимостей) конструкторам задач? – gisek

Смежные вопросы