问题
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