Constructor injection with Quartz.NET 3.0.3 and Simple Injector How To

假如想象 提交于 2020-01-04 02:11:07

问题


I am trying to use Quartz.Net v3.0.3 and Simple Injector in a windows service.

I have a job class below which i would like to inject some dependencies such as my logger into.

public class JobWorker :  IJob
{
    private ILogger _logger;

    public JobWorker(ILogger logger)
    {
        _logger = logger;
    }

    public Task Execute(IJobExecutionContext context)
    {
        return Task.Run(() =>_logger.Log("Do Work"));
    }
}

I tried registering Container.Register<IJob, JobWorker>(); on my DI layer but this doesn't help.

If i remove the injected dependency and simply use the default parameterless constructor the job fires correct.

Accord to the post below by Steven, the suggestion is to create a Factory, however the answer provided is out of date in context of the new framework and i'm completely lost as how to inject dependencies into jobs.

Constructor injection with Quartz.NET and Simple Injector


回答1:


The link provided by @Rabban is still valid and using IServiceProvider is a good design choice, but you can use whatever concrete Container you want.

Here are my 2c based on Rabban's answer using Quartz 3.0.4 and SimpleInjector 4.2.1:

using NLog;
using Quartz;
using Quartz.Spi;
using System;

namespace My.Dear.App.Infrastructure
{

    public class SomeJobFactory : IJobFactory
    {
        private static ILogger logger = LogManager.GetCurrentClassLogger();
        private readonly IServiceProvider serviceProvider;

        public DexJobFactory(IServiceProvider serviceProvider)
        {
            this.serviceProvider = serviceProvider;
        }

        public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
        {
            try
            {
                IJobDetail jobDetail = bundle.JobDetail;
                Type jobType = jobDetail.JobType;
                logger.Debug($"Producing instance of Job '{jobDetail.Key}', class={jobType.FullName}");

                return serviceProvider.GetService(jobType) as IJob;
            }
            catch (Exception ex)
            {
                logger.Error(ex, Constants.ErrorAt, nameof(IJobFactory.NewJob));
                throw new SchedulerException($"Problem instantiating class '{bundle.JobDetail.JobType.FullName}'", ex);
            }
        }

        public void ReturnJob(IJob job)
        {
            var disposable = job as IDisposable;
            disposable?.Dispose();
        }
    }
}

Works like a charm for me.

How to get an instance?

public static async Task RegisterQuartz(Container container)
{
    ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
    IScheduler scheduler = await schedulerFactory.GetScheduler();
    IJobFactory jobFactory = new SomeJobFactory(container);
    scheduler.JobFactory = jobFactory;

    container.RegisterInstance(schedulerFactory);
    container.RegisterInstance(jobFactory);
    container.RegisterInstance(scheduler);
    container.Register<IDearJob, DearJob>();
}

Oh, and don't forget to register your Jobs. Otherwise it may not work.

I suggest creating an Interface for each Job and not using Quartz IJob for that.

public interface IDearJob : IJob { }

public interface DearJob : IDearJob 
{
    private readonly ISomeService service;

    public DearJob(ISomeService service)
    {
        this.service = service;
    }

    public async Task Execute(IJobExecutionContext context) 
    {
        // retrieve context if you need
        await this.service.DoSomethingAsync(/*params*/);
    }
}

Now you can use a breakpoint on Execute. Cheers.

EDIT

P.S.: Steven answer is very good and I think you can play with it to update that context to yours. Now serious, cheers.



来源:https://stackoverflow.com/questions/49057860/constructor-injection-with-quartz-net-3-0-3-and-simple-injector-how-to

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!