雷达智富

首页 > 内容 > 程序笔记 > 正文

程序笔记

Quartz .NET的Job类中使用构造函数依赖注入

2024-06-19 37

Quartz .NET是一个功能强大的作业调度库,用于在.NET应用程序中执行定时任务和后台处理工作。使用.NET C#开发Windows服务时,可以使用Quartz .NET定时执行任务。

使用.NET8开发的Windows服务中,可以使用Nuget安装Quartz .NET包。然后我们可以在Worker.cs的ExecuteAsync方法里创建调度程序。

首先要创建一个Job类,实现IJob接口,代码如下:

public class WebSiteResponseTimeJob : IJob
{
    private readonly ILogger<WebSiteResponseTimeJob> _logger;
    IDbContextFactory<ToolsContext> _contextFactory;
    public WebSiteResponseTimeJob(ILogger<WebSiteResponseTimeJob> logger,IDbContextFactory<ToolsContext> contextFactory)
    {
        _logger = logger;
        _contextFactory = contextFactory;
    }
    public async Task Execute(IJobExecutionContext context)
    {
        try
        {
            _logger.LogInformation("WebSiteResponseTimeJob running at: {time}", DateTimeOffset.Now);
            // ...业务代码
        }
        catch (Exception ex)
        {
            _logger.LogError("WebSiteResponseTimeJob error at: {time}, message: {message}", DateTimeOffset.Now, ex.Message);
        }
    }
}

然后就可以创建和启动调度程序了:

var schedulerFactory = new StdSchedulerFactory();
var scheduler = await schedulerFactory.GetScheduler();
IJobDetail job = JobBuilder.Create<WebSiteResponseTimeJob>()
            .WithIdentity("WebSiteResponseTimeJob")
            .Build();
ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("WebSiteResponseTimeJobTrigger")
    .WithCronSchedule("0 0/10 * * * ?") //从0开始每隔10分钟执行一次
    .Build();
await scheduler.ScheduleJob(job, trigger);
await scheduler.Start();

上面的代码中使用了Cron调度程序。希望每隔十分钟执行一次WebSiteResponseTimeJob任务。实际运行时发现任务没有被触发,而且也没有任何报错信息。

换了一个没有构造函数的Job类后发现可以正常触发,说明是因为Quartz.NET创建Job时不支持构造函数依赖注入。

网上查了一下解决方案是重新实现以下IJobFactory替换原来的JobFactory,在自己实现的JobFactory里创建Job时使用依赖注入注册的对象。

首先创建一个MyJobFactory.cs类,实现IJobFactory接口,代码如下:

public class MyJobFactory : IJobFactory
{
    private readonly IServiceProvider _serviceProvider;

    public MyJobFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }
    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        return _serviceProvider.GetRequiredService(bundle.JobDetail.JobType) as IJob;
    }

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

在Program.cs类里注册要依赖注入的JobFactory和Job,比如我的MyJobFactory和WebSiteResponseTimeJob:

var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddWindowsService(opt =>
{
    opt.ServiceName = "MyTools.Service";
});
builder.Services.AddDbContextFactory<ToolsContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("Tools"));
});
// 注册JobFactory和Job
builder.Services.AddSingleton<IJobFactory, MyJobFactory>();
builder.Services.AddSingleton<WebSiteResponseTimeJob>();

builder.Services.AddHostedService<Worker>();

var host = builder.Build();
host.Run();

然后在创建调度程序的时候替换掉Quartz原来的JobFactory就可以实现依赖注入了,把Worker.cs里的代码做如下修改:

var schedulerFactory = new StdSchedulerFactory();
var scheduler = await schedulerFactory.GetScheduler();
var myJobFactory = _serviceProvider.GetService<IJobFactory>();
if (myJobFactory != null)
{
    scheduler.JobFactory = myJobFactory;
}
IJobDetail job = JobBuilder.Create<WebSiteResponseTimeJob>()
            .WithIdentity("WebSiteResponseTimeJob")
            .Build();
ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("WebSiteResponseTimeJobTrigger")
    .WithCronSchedule("0 0/10 * * * ?")
    .Build();
await scheduler.ScheduleJob(job, trigger);
await scheduler.Start();

这样运行程序就可以正常创建Job对象和执行任务了。

下面是一些常用的Cron表达式:

"0 0 12 * * ?" 每天中午12点触发  "0 15 10 ? * *" 每天上午10:15触发  "0 15 10 * * ?" 每天上午10:15触发  "0 15 10 * * ? *" 每天上午10:15触发  "0 15 10 * * ? 2005" 2005年的每天上午10:15触发  "0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发  "0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发  "0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发  "0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发  "0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发  "0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发  "0 15 10 15 * ?" 每月15日上午10:15触发  "0 15 10 L * ?" 每月最后一日的上午10:15触发  "0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发  "0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发  "0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发  每天早上6点     0 6 * * *     每两个小时     0 */2 * * *  晚上11点到早上8点之间每两个小时,早上八点    0 23-7/2,8 * * *  每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点     0 11 4 * 1-3  1月1日早上4点     0 4 1 1 * 更新于:3个月前
赞一波!2

文章评论

全部评论