How can I configure Quartz in .net core to use dependency injection? I using standard .net core Dependency mechanism. In constructor of class that implements IJob, I need inject some dependencies.
-
1You should probably upgrade to Quartz 3.1 and start using the [built-in dependency injection support](https://www.quartz-scheduler.net/documentation/quartz-3.x/packages/microsoft-di-integration.html). – Marko Lahma Aug 09 '20 at 06:33
6 Answers
You can use the Quartz.Spi.IJobFactory
interface and implement it. The Quartz documentations states:
When a trigger fires, the Job it is associated to is instantiated via the JobFactory configured on the Scheduler. The default JobFactory simply activates a new instance of the job class. You may want to create your own implementation of JobFactory to accomplish things such as having your application’s IoC or DI container produce/initialize the job instance. See the IJobFactory interface, and the associated Scheduler.SetJobFactory(fact) method.
ISchedulerFactory schedulerFactory = new StdSchedulerFactory(properties);
var scheduler = schedulerFactory.GetScheduler();
scheduler.JobFactory = jobFactory;
Edit
The implementation can look like this:
public class JobFactory : IJobFactory
{
protected readonly IServiceProvider Container;
public JobFactory(IServiceProvider container)
{
Container = container;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return Container.GetService(bundle.JobDetail.JobType) as IJob;
}
public void ReturnJob(IJob job)
{
// i couldn't find a way to release services with your preferred DI,
// its up to you to google such things
}
}
To use it with the Microsoft.Extensions.DependencyInjection
create your container like this:
var services = new ServiceCollection();
services.AddTransient<IAuthorizable, AuthorizeService>();
var container = services.BuildServiceProvider();
var jobFactory = new JobFactory(container);
References

- 2,451
- 1
- 19
- 21
-
I know this but how I should build "jobFactory" I build class with IJobFactory but i dont know how i Should code `NewJob` and `ReturnJob` – donex93 Feb 10 '17 at 11:16
-
_I know this but how I should build "jobFactory"_ This was not your question, you wanted to know how to configure Quartz to use DI and this is the correct answer to your Question. To answer how to implement the interface depends on your DI container. Take a look at my edited answer to see a solution i used in some of my projects. – Rabban Feb 10 '17 at 11:22
-
-
its a simple factory that comes from your DI, it can also be just your DI container. This has nothing to do with .Net Core. – Rabban Feb 10 '17 at 11:28
-
for example i use `services.AddTransient
();` so type of my container is: `IServiceCollection` ? – donex93 Feb 10 '17 at 12:05 -
I don't know. I even don't know what DI tool do you use. How do you resolve services from DI? – Rabban Feb 10 '17 at 12:10
-
-
@Rabban Would it be possible to update the answer with an example of how you use the jobFactory to create a job and schedule it? – Zaphod Nov 09 '17 at 07:40
-
2@Zaphod The JobFactory is only needed by Quartz, you schedule the Jobs the same way as without this Factory. You can take a look at one of my other answers that show scheduling: [Job and Trigger creation with helper method](https://stackoverflow.com/a/42627330/6666799), [Multiple Triggers for one Job](https://stackoverflow.com/a/42367132/6666799) or [Job rescheduling](https://stackoverflow.com/a/41590551/6666799). But be aware there seems to be a bug with [CronTrigger scheduling](https://stackoverflow.com/a/44240155/6666799). – Rabban Nov 09 '17 at 08:35
-
@Rabban Thanks! I was not setting the jobfactory on the scheduler. When I did everything works great. – Zaphod Nov 10 '17 at 09:24
Inspired by Rabbans great answer I created a complete implementation of a JobFactory for Microsoft.Extensions.DependencyInjection
:
Implementation
using Microsoft.Extensions.DependencyInjection;
using Quartz;
using Quartz.Spi;
using System;
using System.Collections.Concurrent;
class JobFactory : IJobFactory
{
protected readonly IServiceProvider _serviceProvider;
protected readonly ConcurrentDictionary<IJob, IServiceScope> _scopes = new ConcurrentDictionary<IJob, IServiceScope>();
public JobFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
var scope = _serviceProvider.CreateScope();
IJob job;
try
{
job = scope.ServiceProvider.GetRequiredService(bundle.JobDetail.JobType) as IJob;
}
catch
{
// Failed to create the job -> ensure scope gets disposed
scope.Dispose();
throw;
}
// Add scope to dictionary so we can dispose it once the job finishes
if (!_scopes.TryAdd(job, scope))
{
// Failed to track DI scope -> ensure scope gets disposed
scope.Dispose();
throw new Exception("Failed to track DI scope");
}
return job;
}
public void ReturnJob(IJob job)
{
if (_scopes.TryRemove(job, out var scope))
{
// The Dispose() method ends the scope lifetime.
// Once Dispose is called, any scoped services that have been resolved from ServiceProvider will be disposed.
scope.Dispose();
}
}
}
Usage
// Prepare the DI container
var services = new ServiceCollection();
// Register job
services.AddTransient<MyJob>();
// Register job dependencies
services.AddTransient<IFoo, Foo>();
var container = services.BuildServiceProvider();
// Create an instance of the job factory
var jobFactory = new JobFactory(container);
// Create a Quartz.NET scheduler
var schedulerFactory = new StdSchedulerFactory(properties);
var scheduler = schedulerFactory.GetScheduler();
// Tell the scheduler to use the custom job factory
scheduler.JobFactory = jobFactory;
The implementation has been tested in a .NET Core 2.1 console application with a single job and worked fine. Feel free to leave your feedback or improvement suggestions...

- 5,367
- 3
- 30
- 37
-
please explain how to use it, I am trying `var jobFactory = new JobFactory(serviceProvider);` and then call the injection in constructor of `IJob` but getting `Quartz.SchedulerException` – Tomasz Kowalczyk May 29 '19 at 12:24
-
`job = scope.ServiceProvider.GetRequiredService(bundle.JobDetail.JobType) as IJob;` Throws an exception about not finding the service being registered: `No service for type 'xxx.yyy.TestJob' has been registered.` Do you have an example of a working job registration please? – Seany84 Jun 13 '19 at 16:28
-
@Seany84 you have to register your job with the DI container, e.g. `services.AddTransient
();`. I updated the answer with an example. – CodeZombie Jun 14 '19 at 13:00 -
I know it's an old question, but just wanted to add a 2020 answer:
https://www.quartz-scheduler.net/documentation/quartz-3.x/packages/microsoft-di-integration.html
https://www.quartz-scheduler.net/documentation/quartz-3.x/packages/aspnet-core-integration.html
I find it even easier than the approach that is not using the .NET Core DI. In the project I had to integrate it however, Autofac was using together with MS DI (can't tell you why) and it was complaining about some dependencies, so I had to add the following mapping as well:
services.AddSingleton<ITypeLoadHelper, SimpleTypeLoadHelper>();
The total solution for me looks like this:
services.AddTransient<UpcomingReleasesNotificationJob>();
services.AddSingleton<ITypeLoadHelper, SimpleTypeLoadHelper>();
var jobKey = new JobKey("notificationJob");
services.AddQuartz(q =>
{
q.SchedulerId = "JobScheduler";
q.SchedulerName = "Job Scheduler";
q.UseMicrosoftDependencyInjectionScopedJobFactory();
q.AddJob<UpcomingReleasesNotificationJob>(j => j.WithIdentity(jobKey));
q.AddTrigger(t => t
.WithIdentity("notificationJobTrigger")
.ForJob(jobKey)
.StartNow()
.WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(14, 00))
);
});
services.AddQuartzServer(options =>
{
options.WaitForJobsToComplete = true;
});

- 1,443
- 1
- 9
- 25
-
1If you want to run it inside WorkerService: A. Install-Package Quartz.AspNetCore B. Add to the ConfigureServices: services.AddQuartzServer(q => { q.WaitForJobsToComplete = true; }); More information: https://www.quartz-scheduler.net/documentation/quartz-3.x/packages/aspnet-core-integration.html Enjoy and add – Aharon Ohayon Jan 20 '21 at 13:54
-
@Daniel - how to make all the triggers pause or standby using this version and approach? we need the scheduler object to do so right? – Sanjeevi Subramani Aug 23 '22 at 14:48
No idea if this will be helpful or not but I created my own DI extension for Quartz that you are more then welcome to try: https://github.com/JaronrH/Quartz.DependencyInjection
Short version is that you would use the AddQuartz() method to pass in the [optional] NaveValueCollection config and [required] Scrutor assembly searching you want (see https://andrewlock.net/using-scrutor-to-automatically-register-your-services-with-the-asp-net-core-di-container/). For example:
services.AddQuartz(s => s.FromAssemblyOf<Program>())
This call will:
- Find and automatically register all IJob, IAddScheduledJob, IAddSchedulerListener, IAddTriggerListener, and IAddJobListener implementations found in the assemblies (Scrutor). So, yes, you can use DI in your IJob classes this way!
- Setup a Singleton IScheduler in DI that uses the above DI resources.
- Register an adapter to the IScheduler so that Microsoft's Logging is used for Quartz's logging.
You can then either use provider.StartQuartz() to start the Scheduler (which automatically looks for IApplicationLifetime and registers the Scheduler for Shutdown if available) or use conventional DI to get and start the services (provider.GetService().Start();).
Hope this helps!

- 133
- 6
UseMicrosoftDependencyInjectionJobFactory() allow to create jobs with DI
services.AddQuartz(
q =>
{
q.UseMicrosoftDependencyInjectionJobFactory();
q.ScheduleJob<JobWithDI>(trigger => {});
}
services.AddQuartzHostedService();

- 238
- 2
- 7
Recently I encountered a problem of resolving job's dependencies without existing scope. I was having an exception inside job factory (implemented like in the correct answer) saying that "IServiceProvider was disposed" because the job is scheduled to be exectued after the response returns back to a client.
So, I slightly changed implementation of IJobFactory
in @CodeZombie's answer and it worked. It is different in case of using IServiceScopeFactory
instead of IServiceProvider
- which ensures that every time a new scope is created.
public class CommonJobFactory : IJobFactory
{
private readonly ILogger<CommonJobFactory> _logger;
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly ConcurrentDictionary<IJob, IServiceScope> _scopes = new ConcurrentDictionary<IJob, IServiceScope>();
public CommonJobFactory(
IServiceScopeFactory scopeFactory,
ILogger<CommonJobFactory> logger)
{
_serviceScopeFactory = scopeFactory;
_logger = logger;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
var newScope = _serviceScopeFactory.CreateScope();
try
{
if (newScope.ServiceProvider.GetService(bundle.JobDetail.JobType) is IJob job && _scopes.TryAdd(job, newScope))
return job;
throw new NullReferenceException("Unable to create new job from scope");
}
catch (Exception ex)
{
newScope.Dispose();
_logger.LogError(ex, "Error while constructing {jobType} from scope", bundle.JobDetail.JobType);
throw;
}
}
public void ReturnJob(IJob job)
{
var disposableJob = job as IDisposable;
disposableJob?.Dispose();
if (_scopes.TryRemove(job, out var scope))
scope.Dispose();
}
}

- 1