Планирование Quartz.net Задание с внедрением зависимостей

#c# #dependency-injection #quartz-scheduler

#c# #внедрение зависимостей #quartz.net

Вопрос:

Я работаю над своим первым проектом с EF Core и внедрением зависимостей для контекста БД. Однако я сталкиваюсь с проблемой, потому что Quartz.net 3, похоже, не допускает никаких параметров в классе ImportJob. Итак, мой метод DI в этом случае не работает. Я знаю, что мне нужен новый контекст, потому что это будет выполняться в фоновом режиме, есть ли другой способ создать контекст БД, чтобы я мог выполнить эту задачу?

 public class ImportJob : IJob
{
    private readonly SContext _db;

    //Quartz.net doesn't appear to like that I'm injecting these, 
    //because if I remove this parameter, execute...executes.
    public ImportJob(SContext db)
    {
        _db = db;
    }

    public Task Execute(IJobExecutionContext context)
    {
        var cc = new CC(_db);
        return Task.CompletedTask;
    }
}
  

Ответ №1:

Один из способов — использовать StdSchedulerFactory, фабрику заданий, которая реализует IJobFactory и использует IServiceProvider

Пример

 public class JobFactory : IJobFactory
{
   private readonly IServiceProvider _serviceProvider;

   public JobFactory(IServiceProvider serviceProvider)
      => _serviceProvider = serviceProvider;

   public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
   {
      try
      {
         var jobDetail = bundle.JobDetail;
         var jobType = jobDetail.JobType;
         return _serviceProvider.GetService(jobType) as IJob;
      }
      catch (Exception ex)
      {

         throw new SchedulerException($"Problem instantiating class '{bundle.JobDetail.JobType.FullName}'", ex);
      }
   }

   public void ReturnJob(IJob job)
      => (job as IDisposable)?.Dispose();
}
  

В зависимости от вашей инфраструктуры DI регистрации будут выглядеть примерно так

 // register, your container as an IServiceProvider
container.RegisterInstance<IServiceProvider>(container);

// create the scheduler
var scheduler = await StdSchedulerFactory.GetDefaultScheduler(cancellationTokenSource.Token);

// add your factory to the scheduler
scheduler.JobFactory = new JobFactory(container);

// register the scheduler
container.RegisterInstance(scheduler);

// register your jobs

container.Collection.Register<IJob>(GetType().Assembly);
  

Тогда ваши задания могут выглядеть следующим образом

 public class ImportJob : IJob
{
    private readonly SContext _db;

    //Quartz.net doesn't appear to like that I'm injecting these, 
    //because if I remove this parameter, execute...executes.
    public ImportJob(SContext db)
    {
        _db = db;
    }

    public Task Execute(IJobExecutionContext context)
    {
        var cc = new CC(_db);
        return Task.CompletedTask;
    }
}
  

Примечание: Это основная идея, а не полный пример, и это будет во многом зависеть от ваших собственных настроек и фреймворка

Короче говоря, то, что вышеописанное делает, — это когда Quartz создает задание, оно использует вашу фабрику и контейнер для запуска задания, допускающего внедрение.

Комментарии:

1. Я новичок в DI amp; EF Core, я не вижу, где находится моя _db в вашем примере?

2. @JoeStellato Это проблема DI / Quartz, а не проблема с заданиями. что он делает, так это позволяет вашим заданиям поддерживать DI. он делает это, используя вашу собственную фабрику заданий и ваш контейнер для запуска задания и DI