传递Ninject内核是一个好做法吗?

本文关键字:一个 内核 Ninject 传递 | 更新日期: 2023-09-27 17:51:14

我正在编写一个执行几个任务的小框架。有些任务需要通过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; }

有人知道如何解决这个问题吗?

我可以将内核传递给不同的任务,但是有些东西告诉我这不是正确的方法。

亲切的问候

传递Ninject内核是一个好做法吗?

你应该充分利用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如前所述,通过属性进行依赖注入并不是最好的解决方案。在这个例子中,你也可以使用构造函数注入。

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

在这种情况下我通常使用工厂模式。在调度程序中,可以将任务工厂作为依赖项。这个工厂也可以有多个方法来创建不同类型的任务。

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