.net核心石英依赖注入

时间:2017-02-10 11:02:24

标签: c# .net dependency-injection asp.net-core quartz.net

如何在 .net 核心中配置Quartz以使用依赖注入?我使用标准的.net核心依赖机制。在实现 IJob 的类的构造函数中,我需要注入一些依赖项。

4 个答案:

答案 0 :(得分:10)

您可以使用Quartz.Spi.IJobFactory界面并实施它。 Quartz文档声明:

  

当触发器触发时,与其关联的Job将通过Scheduler上配置的JobFactory实例化。默认的JobFactory只是激活作业类的新实例。您可能希望创建自己的JobFactory实现来完成诸如让应用程序的IoC或DI容器生成/初始化作业实例之类的事情。   请参阅IJobFactory接口和相关的Scheduler.SetJobFactory(fact)方法。

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);

<强>参考

  1. Quartz documentation

  2. Api

答案 1 :(得分:7)

我知道这是一个老问题,但只想添加一个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;
});

答案 2 :(得分:1)

Rabbans great answer的启发,我为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();
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控制台应用程序中通过一项工作进行了测试,并且工作良好。 随时留下您的反馈或改进建议...

答案 3 :(得分: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资源设置Singleton IScheduler。
  • 将适配器注册到IScheduler,以便将Microsoft的Logging用于Quartz的日志。

然后,您可以使用provider.StartQuartz()启动调度程序(它将自动查找IApplicationLifetime并注册调度程序以进行关机(如果可用)),也可以使用常规DI来获取和启动服务(provider.GetService()。Start)。 ();)。

希望这会有所帮助!