.net Core Quartz 依赖注入
.net Core Quartz Dependency Injection
如何在 .net 内核中配置 Quartz 以使用依赖注入?我使用标准的 .net 核心依赖机制。在实现 IJob 的 class 的构造函数中,我需要注入一些依赖项。
您可以使用Quartz.Spi.IJobFactory
接口并实现它。 Quartz 文档指出:
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;
编辑
实现可以如下所示:
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
}
}
要将它与 Microsoft.Extensions.DependencyInjection
一起使用,请像这样创建容器:
var services = new ServiceCollection();
services.AddTransient<IAuthorizable, AuthorizeService>();
var container = services.BuildServiceProvider();
var jobFactory = new JobFactory(container);
参考资料
受到 的启发,我为 Microsoft.Extensions.DependencyInjection
创建了一个完整的 JobFactory 实现:
实施
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();
}
}
}
用法
// 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;
该实现已在 .NET Core 2.1 控制台应用程序中通过单个作业进行测试并且运行良好。
欢迎留下您的反馈或改进建议...
不知道这是否有用,但我为 Quartz 创建了自己的 DI 扩展,欢迎您尝试:https://github.com/JaronrH/Quartz.DependencyInjection
简短版本是您将使用 AddQuartz() 方法传入 [可选] NaveValueCollection 配置和 [必需] Scrutor 程序集搜索您想要的(参见 https://andrewlock.net/using-scrutor-to-automatically-register-your-services-with-the-asp-net-core-di-container/)。例如:
services.AddQuartz(s => s.FromAssemblyOf<Program>())
此调用将:
- 查找并自动注册在程序集 (Scrutor) 中找到的所有 IJob、IAddScheduledJob、IAddSchedulerListener、IAddTriggerListener 和 IAddJobListener 实现。所以,是的,您可以通过这种方式在 IJob 类 中使用 DI!
- 在使用上述 DI 资源的 DI 中设置单例 IScheduler。
- 向 IScheduler 注册一个适配器,以便将 Microsoft 的日志记录用于 Quartz 的日志记录。
然后您可以使用 provider.StartQuartz() 启动调度程序(它会自动查找 IApplicationLifetime 并在可用时为关闭注册调度程序)或使用传统的 DI 来获取和启动服务(provider.GetService().开始();).
希望对您有所帮助!
我知道这是一个老问题,但只想添加一个 2020 年的答案:
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
我发现它比不使用 .NET Core DI 的方法更容易。
在我不得不集成它的项目中,Autofac 与 MS DI 一起使用(不能告诉你为什么)并且它抱怨一些依赖关系,所以我还必须添加以下映射:
services.AddSingleton<ITypeLoadHelper, SimpleTypeLoadHelper>();
我的完整解决方案如下所示:
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;
});
UseMicrosoftDependencyInjectionJobFactory() 允许使用 DI 创建作业
services.AddQuartz(
q =>
{
q.UseMicrosoftDependencyInjectionJobFactory();
q.ScheduleJob<JobWithDI>(trigger => {});
}
services.AddQuartzHostedService();
如何在 .net 内核中配置 Quartz 以使用依赖注入?我使用标准的 .net 核心依赖机制。在实现 IJob 的 class 的构造函数中,我需要注入一些依赖项。
您可以使用Quartz.Spi.IJobFactory
接口并实现它。 Quartz 文档指出:
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;
编辑
实现可以如下所示:
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
}
}
要将它与 Microsoft.Extensions.DependencyInjection
一起使用,请像这样创建容器:
var services = new ServiceCollection();
services.AddTransient<IAuthorizable, AuthorizeService>();
var container = services.BuildServiceProvider();
var jobFactory = new JobFactory(container);
参考资料
受到 Microsoft.Extensions.DependencyInjection
创建了一个完整的 JobFactory 实现:
实施
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();
}
}
}
用法
// 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;
该实现已在 .NET Core 2.1 控制台应用程序中通过单个作业进行测试并且运行良好。 欢迎留下您的反馈或改进建议...
不知道这是否有用,但我为 Quartz 创建了自己的 DI 扩展,欢迎您尝试:https://github.com/JaronrH/Quartz.DependencyInjection
简短版本是您将使用 AddQuartz() 方法传入 [可选] NaveValueCollection 配置和 [必需] Scrutor 程序集搜索您想要的(参见 https://andrewlock.net/using-scrutor-to-automatically-register-your-services-with-the-asp-net-core-di-container/)。例如:
services.AddQuartz(s => s.FromAssemblyOf<Program>())
此调用将:
- 查找并自动注册在程序集 (Scrutor) 中找到的所有 IJob、IAddScheduledJob、IAddSchedulerListener、IAddTriggerListener 和 IAddJobListener 实现。所以,是的,您可以通过这种方式在 IJob 类 中使用 DI!
- 在使用上述 DI 资源的 DI 中设置单例 IScheduler。
- 向 IScheduler 注册一个适配器,以便将 Microsoft 的日志记录用于 Quartz 的日志记录。
然后您可以使用 provider.StartQuartz() 启动调度程序(它会自动查找 IApplicationLifetime 并在可用时为关闭注册调度程序)或使用传统的 DI 来获取和启动服务(provider.GetService().开始();).
希望对您有所帮助!
我知道这是一个老问题,但只想添加一个 2020 年的答案:
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
我发现它比不使用 .NET Core DI 的方法更容易。 在我不得不集成它的项目中,Autofac 与 MS DI 一起使用(不能告诉你为什么)并且它抱怨一些依赖关系,所以我还必须添加以下映射:
services.AddSingleton<ITypeLoadHelper, SimpleTypeLoadHelper>();
我的完整解决方案如下所示:
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;
});
UseMicrosoftDependencyInjectionJobFactory() 允许使用 DI 创建作业
services.AddQuartz(
q =>
{
q.UseMicrosoftDependencyInjectionJobFactory();
q.ScheduleJob<JobWithDI>(trigger => {});
}
services.AddQuartzHostedService();