.NET Core 實現(xiàn)后臺任務(wù)(定時任務(wù))BackgroundService(二)
原文連接:http://www.rzrgm.cn/ysmc/p/16468560.html
在上一篇文檔中說到使用 IHostedService 接口實現(xiàn)定時任務(wù) 傳送門,其中,有小伙伴就問到,為什么不使用 BackgroundService,我個人覺得使用什么技術(shù),應(yīng)該取決于需求,代碼只是一種工具,用得順手對于編碼人員來說,我個人感覺還是非常重要的;正好也說到了 BackgroundService,那這一篇文檔就簡單說一下它吧。
首先我們看一下官方的說明,學(xué)習(xí)代碼一定要看官方的文檔,盡管有時候會有點晦澀難懂,但肯定是最正確的:
BackgroundService 基類
BackgroundService 是用于實現(xiàn)長時間運行的 IHostedService 的基類。
調(diào)用 ExecuteAsync(CancellationToken) 來運行后臺服務(wù)。 實現(xiàn)返回一個 Task,其表示后臺服務(wù)的整個生存期。
在 ExecuteAsync 變?yōu)楫惒剑ɡ缤ㄟ^調(diào)用 await)之前,不會啟動任何其他服務(wù)。 避免在 ExecuteAsync 中執(zhí)行長時間的阻塞初始化工作。
StopAsync(CancellationToken) 中的主機塊等待完成 ExecuteAsync。
調(diào)用 IHostedService.StopAsync 時,將觸發(fā)取消令牌。 當(dāng)激發(fā)取消令牌以便正常關(guān)閉服務(wù)時,ExecuteAsync 的實現(xiàn)應(yīng)立即完成。 否則,服務(wù)將在關(guān)閉超時后不正常關(guān)閉。
StartAsync 應(yīng)僅限于短期任務(wù),因為托管服務(wù)是按順序運行的,在 StartAsync 運行完成之前不會啟動其他服務(wù)。 長期任務(wù)應(yīng)放置在 ExecuteAsync 中。
針對第一點“BackgroundService 是用于實現(xiàn)長時間運行的 IHostedService 的基類”,我們先看看 BackgroundService 的源碼:
1 public abstract class BackgroundService : IHostedService, IDisposable 2 { 3 private Task _executingTask; 4 private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource(); 5 6 /// <summary> 7 /// This method is called when the <see cref="IHostedService"/> starts. The implementation should return a task that represents 8 /// the lifetime of the long running operation(s) being performed. 9 /// /// </summary> 10 /// <param name="stoppingToken">Triggered when <see cref="IHostedService.StopAsync(CancellationToken)"/> is called.</param> 11 /// <returns>A <see cref="Task"/> that represents the long running operations.</returns> 12 protected abstract Task ExecuteAsync(CancellationToken stoppingToken); 13 14 /// <summary> 15 /// Triggered when the application host is ready to start the service. 16 /// </summary> 17 /// <param name="cancellationToken">Indicates that the start process has been aborted.</param> 18 public virtual Task StartAsync(CancellationToken cancellationToken) 19 { 20 // Store the task we're executing 21 _executingTask = ExecuteAsync(_stoppingCts.Token); 22 23 // If the task is completed then return it, this will bubble cancellation and failure to the caller 24 if (_executingTask.IsCompleted) 25 { 26 return _executingTask; 27 } 28 29 // Otherwise it's running 30 return Task.CompletedTask; 31 } 32 33 /// <summary> 34 /// Triggered when the application host is performing a graceful shutdown. 35 /// </summary> 36 /// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param> 37 public virtual async Task StopAsync(CancellationToken cancellationToken) 38 { 39 // Stop called without start 40 if (_executingTask == null) 41 { 42 return; 43 } 44 45 try 46 { 47 // Signal cancellation to the executing method 48 _stoppingCts.Cancel(); 49 } 50 finally 51 { 52 // Wait until the task completes or the stop token triggers 53 await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken)); 54 } 55 56 } 57 58 public virtual void Dispose() 59 { 60 _stoppingCts.Cancel(); 61 } 62 }
以上代碼很好的解答了小伙伴提出“為什么不使用 BackgroundService”的問題,在上一篇文章中,評論區(qū)的一位大佬也很好的回答了這位小伙伴的問題,我這里引用下這位大佬的原話:“BackgroundService 是 IHostedService的一個簡單實現(xiàn),內(nèi)部IHostedService 的StartAsync調(diào)用了ExecuteAsync”,本質(zhì)上就是使用了 IHostedService;
讓我們回到正題,怎么用 BackgroundService 實現(xiàn)定時任務(wù)呢,老規(guī)矩,上代碼:
首先,創(chuàng)建一個服務(wù)接口,定義需要實現(xiàn)的任務(wù),以及對應(yīng)的實現(xiàn),如果需要執(zhí)行異步方法,記得加上 await,不然任務(wù)將不會等待執(zhí)行結(jié)果,直接進行下一個任務(wù)。
1 public class TaskWorkService : ITaskWorkService 2 { 3 public async Task TaskWorkAsync(CancellationToken stoppingToken) 4 { 5 while (!stoppingToken.IsCancellationRequested) 6 { 7 //執(zhí)行任務(wù) 8 Console.WriteLine($"{DateTime.Now}"); 9 10 //周期性任務(wù),于上次任務(wù)執(zhí)行完成后,等待5秒,執(zhí)行下一次任務(wù) 11 await Task.Delay(500); 12 } 13 } 14 }
注冊服務(wù)
builder.Services.AddScoped<ITaskWorkService, TaskWorkService>();
創(chuàng)建后臺服務(wù)類,繼承基類 BackgroundService,這里需要注意的是,要在 BackgroundService 中使用有作用域的服務(wù),請創(chuàng)建作用域, 默認情況下,不會為托管服務(wù)創(chuàng)建作用域,得自己管理服務(wù)的生命周期,切記!于構(gòu)造函數(shù)中注入 IServiceProvider即可。
1 public class BackgroundServiceDemo : BackgroundService 2 { 3 private readonly IServiceProvider _services; 4 5 public BackgroundServiceDemo(IServiceProvider services) 6 { 7 _services = services; 8 } 9 10 protected override async Task ExecuteAsync(CancellationToken stoppingToken) 11 { 12 using var scope = _services.CreateScope(); 13 14 var taskWorkService = scope.ServiceProvider.GetRequiredService<ITaskWorkService>(); 15 16 await taskWorkService.TaskWorkAsync(stoppingToken); 17 } 18 }
最后別忘了這個類也是需要注冊的,注冊方式與 IHostedService 接口的方式一樣
builder.Services.AddHostedService<BackgroundServiceDemo>();
大功告成,F(xiàn)5看看效果吧

寫在最后
Bootstrap Blazor 官網(wǎng)地址:https://www.blazor.zone
希望大佬們看到這篇文章,能給項目點個star支持下,感謝各位!
star流程:
1、訪問點擊項目鏈接:BootstrapBlazor
2、點擊star,如下圖,即可完成star,關(guān)注項目不迷路:

另外還有兩個GVP項目,大佬們方便的話也點下star唄,非常感謝:
BootstrapAdmin 項目地址:
https://gitee.com/LongbowEnterprise/BootstrapAdmin
SliderCaptcha 項目地址:
https://gitee.com/LongbowEnterprise/SliderCaptcha
交流群(QQ)歡迎加群討論
BA & Blazor ①(795206915) BA & Blazor ②(675147445)


本文來自博客園,作者:一事冇誠,轉(zhuǎn)載請注明原文鏈接:http://www.rzrgm.cn/ysmc/p/16468560.html

浙公網(wǎng)安備 33010602011771號