传递 Ninject 内核是一个好习惯吗?
Is it a good practice to pass the Ninject kernel around?
我正在编写一个执行几个任务的小型框架。
有些任务需要通过 Ninject.
注入的特定属性
假设我的基础 class 中有以下构造函数代表单个任务:
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; }
有人知道如何解决这个问题吗?
我可以将内核传递给不同的任务,但有些东西告诉我这不是正确的方法。
亲切的问候
在这种情况下,我通常使用工厂模式。在调度程序中,您可以将任务工厂作为依赖项。这个工厂也可以有多种方法来创建不同类型的任务。
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));
}
}
你应该利用 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;
}
}
额外参数注入:
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);
}
我正在编写一个执行几个任务的小型框架。 有些任务需要通过 Ninject.
注入的特定属性假设我的基础 class 中有以下构造函数代表单个任务:
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; }
有人知道如何解决这个问题吗?
我可以将内核传递给不同的任务,但有些东西告诉我这不是正确的方法。
亲切的问候
在这种情况下,我通常使用工厂模式。在调度程序中,您可以将任务工厂作为依赖项。这个工厂也可以有多种方法来创建不同类型的任务。
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));
}
}
你应该利用 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;
}
}
额外参数注入:
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);
}