WebAPI-定时任务
Hosted Services
IHostedService接口
IHostedService 是一个接口,它定义了两个方法:StartAsync(CancellationToken) 和 StopAsync(CancellationToken)。这两个方法分别用于启动和停止后台服务。当你实现这个接口时,你需要自己处理所有的逻辑,包括如何开始、执行任务以及优雅地关闭服务
BackgroundService抽象类
BackgroundService 是一个抽象类,它实现了 IHostedService 接口,并且提供了一个默认的实现来简化开发过程。它引入了一个名为 ExecuteAsync(CancellationToken) 的虚方法,你可以在子类中重写这个方法来实现具体的业务逻辑。BackgroundService 会自动处理一些常见的任务,比如在应用程序关闭时正确地停止服务。
自动触发
BackgroundService 中定义的任务是自动触发的,无需手动触发。当你将一个实现了 IHostedService 接口(或继承自 BackgroundService)的服务注册到 ASP.NET Core 的依赖注入容器中时,ASP.NET Core 会在应用程序启动时自动调用该服务的 StartAsync 方法,并在应用程序关闭时调用 StopAsync 方法
program
1 2
| builder.Services.AddHostedService<MyTask>();
|
MyTask
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class MyTask: BackgroundService { protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { Console.WriteLine("执行定时任务: " + DateTime.Now);
await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken); } } public override void Dispose() { base.Dispose(); } }
|
Timer
在 .NET 中,System.Threading.Timer 类提供了一种简单的方式来执行定时任务。它允许你指定一个回调方法,在经过一段指定的时间后调用该方法。Timer 类非常适合用于需要定期或延时执行的任务
1 2 3 4 5 6
| public Timer( TimerCallback callback, object state, int dueTime, int period )
|
- callback:一个
TimerCallback 委托,指向当定时器触发时要调用的方法。
- state:传递给回调方法的任意对象。这个参数可以用来传递数据到回调方法中。
- dueTime:定时器启动前的初始延迟时间(以毫秒为单位)。
- period:定时器触发之间的间隔时间(以毫秒为单位)。如果设置为 -1 或
Timeout.Infinite,则定时器仅触发一次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class MyTask : BackgroundService { private Timer _timer;
protected override Task ExecuteAsync(CancellationToken stoppingToken) { _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(30));
return Task.CompletedTask; }
private void DoWork(object state) { Console.WriteLine("执行定时任务: " + DateTime.Now);
if (stoppingToken.IsCancellationRequested) { _timer.Dispose(); } }
public override void Dispose() { _timer?.Dispose(); base.Dispose(); } }
|
Cron表达式
cron表达式是一个字符串,通过crom表达式可以定义任务触发的时间
构成规则:分为6或者个域,由空格分开,每个域代表一个含义
注:周和日应该只有一个出现,而为空的时候填写?
Cron - 在线Cron表达式生成器
NCrontab
如果想要实现指定规则去执行定时任务的话,仅仅通过Hosted Services是不行的
通过导入第三方库NCrontab,解析cron表达式,通过Timer来配置循环执行的定时任务,再通过Hosted Services来配置好后台任务
注: 因为Dal层是scope注入范围,而定时任务是单例,直接注入会出现异常,使用IServiceScopeFactory获取scope的Dal层对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class MyTask : BackgroundService { private readonly CrontabSchedule _schedule; private Timer? _timer; private readonly ILogger<MyTask> _logger;
public MyTask(ILogger<MyTask> logger) { _logger = logger; _schedule = CrontabSchedule.Parse("5/5 * * * * *", new CrontabSchedule.ParseOptions { IncludingSeconds = true }); }
protected override Task ExecuteAsync(CancellationToken stoppingToken) { _timer = new Timer(DoWork, null, _schedule.GetNextOccurrence(DateTime.Now) - DateTime.Now, TimeSpan.FromMilliseconds(-1));
return Task.CompletedTask; }
private void DoWork(object state) { Console.WriteLine("执行每日任务: " + DateTime.Now); _timer.Change(_schedule.GetNextOccurrence(DateTime.Now) - DateTime.Now, TimeSpan.FromMilliseconds(-1)); }
public override void Dispose() { base.Dispose(); _timer?.Dispose(); } }
|