使用Web应用程序时,通常需要在后台执行某些任务。 在某些情况下,这些任务应该以预定的时间间隔执行。
Quartz.NET是流行的Java作业调度框架的开源.NET端口。 它已经使用了很长时间,并且为使用Cron表达式提供了出色的支持。 您可以在此处的早期文章中了解有关Quartz.NET的更多信息。
本文讨论了如何在ASP.NET Core中使用Quartz.NET来调度后台作业。
若要使用本文提供的代码示例,您应该在系统中安装Visual Studio 2019。 如果您还没有副本,则可以在此处下载Visual Studio 2019 。
首先,让我们在Visual Studio中创建一个ASP.NET Core项目。 假设系统中已安装Visual Studio 2019,请按照下面概述的步骤在Visual Studio中创建一个新的ASP.NET Core项目。
这将在Visual Studio中创建一个新的ASP.NET Core API项目。 在“解决方案资源管理器”窗口中选择Controllers解决方案文件夹,然后单击“添加-> Controller…”以创建一个名为DefaultController的新控制器。
接下来,要使用Quartz,您应该从NuGet安装Quartz软件包。 您可以通过Visual Studio 2019 IDE中的NuGet程序包管理器来执行此操作,也可以通过在NuGet程序包管理器控制台上执行以下命令来执行此操作:
Install-Package Quartz
Quartz.NET中的三个主要概念是作业,触发器和调度程序。 作业包含执行任务或要执行的作业的代码。 作业由实现IJob接口的类表示。 触发器用于指定作业的时间表和其他详细信息。 您可以利用触发器来指定应如何执行作业。 调度程序是负责根据预定义的调度轮询和执行作业的组件。
应该注意的是,一个应用程序中可以有多个调度程序。 但是,为了简单起见,我们在这里仅使用一个调度程序。 以下代码段说明了如何创建调度程序实例。
var scheduler = StdSchedulerFactory.GetDefaultScheduler().GetAwaiter().GetResult();
一旦创建了调度程序,就可以在Startup.cs文件的ConfigureServices方法中使用以下代码将调度程序实例添加为单例服务。
services.AddSingleton(scheduler);
要启动和停止调度程序,我们将利用托管服务。 为此,您需要创建一个实现IHostingService接口的类,如下面给出的代码片段所示。
public class CustomQuartzHostedService : IHostedService
{
private readonly IScheduler _scheduler;
public CustomQuartzHostedService(IScheduler scheduler)
{
_scheduler = scheduler;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
await _scheduler?.Start(cancellationToken);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await _scheduler?.Shutdown(cancellationToken);
}
}
请注意,您应该使用下面给出的代码片段在ConfigureServices方法中的服务集合中注册托管服务。
services.AddHostedService();
这是更新的ConfigureServices方法,供您参考:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
var scheduler =
StdSchedulerFactory.GetDefaultScheduler().GetAwaiter().GetResult();
services.AddSingleton(scheduler);
services.AddHostedService();
}
如前所述,作业是一个实现IJob接口并包含Execute()方法的类。 Execute()方法接受IJobExecutionContext类型的实例。
以下代码段说明了一个包含异步Execute()方法的作业类。 此方法包含与您的工作应执行的任务相对应的代码。
[DisallowConcurrentExecution]
public class NotificationJob : IJob
{
private readonly ILogger _logger;
public NotificationJob(ILogger logger)
{
_logger = logger;
}
public Task Execute(IJobExecutionContext context)
{
_logger.LogInformation("Hello world!");
return Task.CompletedTask;
}
}
作业工厂是一个继承IJobFactory接口并实现NewJob()和ReturnJob()方法的类。 以下代码段可用于创建可以创建和返回作业实例的工厂类。
public class CustomQuartzJobFactory : IJobFactory
{
private readonly IServiceProvider _serviceProvider;
public CustomQuartzJobFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IJob NewJob(TriggerFiredBundle triggerFiredBundle,
IScheduler scheduler)
{
var jobDetail = triggerFiredBundle.JobDetail;
return (IJob)_serviceProvider.GetService(jobDetail.JobType);
}
public void ReturnJob(IJob job) { }
}
请注意,此实现没有利用作业池。 如果要使用作业池,则应更改NewJob()方法,然后实现ReturnJob()方法。
我们将使用一个自定义类来存储与作业相关的元数据,即作业ID,名称等。以下类表示作业元数据类。
public class JobMetadata
{
public Guid JobId { get; set; }
public Type JobType { get; }
public string JobName { get; }
public string CronExpression { get; }
public JobMetadata(Guid Id, Type jobType, string jobName,
string cronExpression)
{
JobId = Id;
JobType = jobType;
JobName = jobName;
CronExpression = cronExpression;
}
}
接下来,我们需要实现一个托管服务。 托管服务是一个实现IHostedService接口并启动Quartz调度程序的类。 下面的代码清单说明了自定义托管服务类。
public class CustomQuartzHostedService : IHostedService
{
private readonly ISchedulerFactory schedulerFactory;
private readonly IJobFactory jobFactory;
private readonly JobMetadata jobMetadata;
public CustomQuartzHostedService(ISchedulerFactory
schedulerFactory,
JobMetadata jobMetadata,
IJobFactory jobFactory)
{
this.schedulerFactory = schedulerFactory;
this.jobMetadata = jobMetadata;
this.jobFactory = jobFactory;
}
public IScheduler Scheduler { get; set; }
public async Task StartAsync(CancellationToken cancellationToken)
{
Scheduler = await schedulerFactory.GetScheduler();
Scheduler.JobFactory = jobFactory;
var job = CreateJob(jobMetadata);
var trigger = CreateTrigger(jobMetadata);
await Scheduler.ScheduleJob(job, trigger, cancellationToken);
await Scheduler.Start(cancellationToken);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await Scheduler?.Shutdown(cancellationToken);
}
private ITrigger CreateTrigger(JobMetadata jobMetadata)
{
return TriggerBuilder.Create()
.WithIdentity(jobMetadata.JobId.ToString())
.WithCronSchedule(jobMetadata.CronExpression)
.WithDescription($"{jobMetadata.JobName}")
.Build();
}
private IJobDetail CreateJob(JobMetadata jobMetadata)
{
return JobBuilder
.Create(jobMetadata.JobType)
.WithIdentity(jobMetadata.JobId.ToString())
.WithDescription($"{jobMetadata.JobName}")
.Build();
}
}
下面的代码片段显示了Startup类的ConfigureServices方法的完整代码。
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton(new JobMetadata(Guid.NewGuid(), typeof(NotificationJob),"Notification Job", "0/10 * * * * ?"));
services.AddHostedService();
}
这就是您要做的! 当您执行应用程序时,您会发现NotificationJob类的Execute()方法每10秒运行一次。
Quartz.NET是在您的应用程序中实现调度程序的理想选择。 您可以利用Quartz.NET中的持久性功能将作业存储在SQL Server,PostgreSQL或SQLite等数据库中。
From: https://www.infoworld.com/article/3529418/how-to-schedule-jobs-using-quartznet-in-aspnet-core.html