.NET 8 強大功能 IHostedService 與 BackgroundService 實戰(zhàn)教程
前言
在.NET 8中,IHostedService 和 BackgroundService 兩個核心接口的引入,增強了項目開發(fā)中處理定時任務(wù)的能力。這兩個接口不僅簡化了定時任務(wù)、后臺處理作業(yè)以及定期維護任務(wù)的實現(xiàn)過程,還提升了在ASP.NET Core 或任何基于.NET的宿主應(yīng)用程序中的集成與管理效率。
IHostedService接口提供了一個基本的框架,允許自定義后臺服務(wù)的啟動和停止邏輯。通過實現(xiàn)該接口,可以靈活地控制服務(wù)的生命周期,確保任務(wù)在應(yīng)用程序啟動時自動運行,并在應(yīng)用程序關(guān)閉時結(jié)束。
而 BackgroundService 類則是對 IHostedService 接口的進一步封裝,它專為需要長時間運行的任務(wù)而設(shè)計。
通過繼承 BackgroundService并重寫其 ExecuteAsync方法,可以輕松地實現(xiàn)復(fù)雜的后臺邏輯,如循環(huán)執(zhí)行的任務(wù)、基于時間間隔的操作等。這種設(shè)計模式讓代碼的可讀性和可維護性變的更好。
利用這些功能,可以快速構(gòu)建出高效、可靠的定時任務(wù)系統(tǒng),用于執(zhí)行諸如消息推送、數(shù)據(jù)更新、定時發(fā)布等關(guān)鍵業(yè)務(wù)操作。這些任務(wù)可以在不影響應(yīng)用程序主流程的情況下獨立運行,從而提高了整個系統(tǒng)的性能和穩(wěn)定性。
介紹
.NET 中的后臺服務(wù)允許在后臺獨立于主應(yīng)用程序線程運行任務(wù)。這對于需要連續(xù)或定期運行而不阻塞主應(yīng)用程序流的任務(wù)至關(guān)重要。
IHostedService
IHostedService 是一個簡單的接口,用于實現(xiàn)后臺服務(wù)。當(dāng)需要實現(xiàn)自定義的托管服務(wù)時,可以通過實現(xiàn)這個接口來創(chuàng)建。
該接口定義了兩個方法:StartAsync(CancellationToken cancellationToken) 和 StopAsync(CancellationToken cancellationToken),分別用于啟動和停止服務(wù)。
BackgroundService
BackgroundService 是一個抽象類,它繼承自 IHostedService 并提供了更簡潔的方式來編寫后臺服務(wù)。它通常用于需要長時間運行的任務(wù),如監(jiān)聽器、工作隊列處理器等。通過重寫 ExecuteAsync(CancellationToken stoppingToken)方法,可以在其中編寫任務(wù)的邏輯。ExecuteAsync方法會循環(huán)在后臺執(zhí)行,直到服務(wù)停止。
IHostedService 示例
1、注冊服務(wù)
Program.cs 中添加配置,.NET 5 及以下在需要在 Startup.cs 注冊服務(wù)。
// .NET 8 using ManageCore.Api; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddHostedService<DemoHostedService>(); var app = builder.Build();
2、創(chuàng)建服務(wù)接口
創(chuàng)建一個類,該類繼承 IHostedService 接口,并實現(xiàn)該接口成員.
在不需要定時執(zhí)行任務(wù)的時候,也可以在這里進行應(yīng)用啟動后的操作,例如創(chuàng)建 RabbitMQ 連接
using Microsoft.Extensions.Hosting;
namespace ManageCore.Api
{
public class DemoHostedService : IHostedService, IDisposable
{
private Timer? _timer;
public Task StartAsync(CancellationToken cancellationToken)
{
_timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
private void DoWork(object? state)
{
Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
}
public Task StopAsync(CancellationToken cancellationToken)
{
Console.WriteLine("StopAsync");
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
}上面的Demo代碼非常簡單,應(yīng)用在運行后,會去執(zhí)行 StartAsync 函數(shù),應(yīng)用關(guān)閉執(zhí)行 StopAsync,由于這里使用的定時器,所以每過5秒都會執(zhí)行一次 DoWork 函數(shù)。
3、運行效果

4、IHostedService 說明
注意:定時是不等待任務(wù)執(zhí)行完成,只要時間一到,就會調(diào)用 DoWork 函數(shù),所以適合一些簡單、特定的場景。
以下為官方文檔對 IHostedService 接口 的說明
IHostedService 接口為主機托管的對象定義了兩種方法:
- StartAsync(CancellationToken)
- StopAsync(CancellationToken)
StartAsync(CancellationToken) 包含用于啟動后臺任務(wù)的邏輯。 在以下操作之前調(diào)用 `StartAsync`:已配置應(yīng)用的請求處理管道。已啟動服務(wù)器且已觸發(fā) IApplicationLifetime.ApplicationStarted。
StartAsync應(yīng)僅限于短期任務(wù),因為托管服務(wù)是按順序運行的,在 StartAsync 運行完成之前不會啟動其他服務(wù)。
StopAsync(CancellationToken) 在主機執(zhí)行正常關(guān)閉時觸發(fā)。 StopAsync`包含結(jié)束后臺任務(wù)的邏輯。 實現(xiàn) IDisposable 和終結(jié)器(析構(gòu)函數(shù))以處置任何非托管資源。
默認情況下,取消令牌會有五秒超時,以指示關(guān)閉進程不再正常。 在令牌上請求取消時:
- 應(yīng)中止應(yīng)用正在執(zhí)行的任何剩余后臺操作。
- StopAsync 中調(diào)用的任何方法都應(yīng)及時返回。
但是,在請求取消后,將不會放棄任務(wù),調(diào)用方會等待所有任務(wù)完成。
如果應(yīng)用意外關(guān)閉(例如,應(yīng)用的進程失?。瑒t可能不會調(diào)用 StopAsync。 因此,在 StopAsync 中執(zhí)行的任何方法或操作都可能不會發(fā)生。
若要延長默認值為 5 秒的關(guān)閉超時值,請設(shè)置:
- ShutdownTimeout(當(dāng)使用通用主機時)
- 使用 Web 主機時為關(guān)閉超時值主機配置設(shè)置
托管服務(wù)在應(yīng)用啟動時激活一次,在應(yīng)用關(guān)閉時正常關(guān)閉。 如果在執(zhí)行后臺任務(wù)期間引發(fā)錯誤,即使未調(diào)用 StopAsync,也應(yīng)調(diào)用 Dispose。
BackgroundService 示例
1、注冊服務(wù)
首先,同樣需要在配置中注冊服務(wù)接口。
using ManageCore.Api; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddScoped<IDemoTaskWorkService, DemoTaskWorkService>();
2、BackgroundService 源碼
查看 BackgroundService 的源碼,幫助我們理解BackgroundService 實現(xiàn)原理。BackgroundService 是 IHostedService的一個簡單實現(xiàn),內(nèi)部 IHostedService 的 StartAsync 調(diào)用了 ExecuteAsync,本質(zhì)上就是使用了 IHostedService。
public abstract class BackgroundService : IHostedService, IDisposable
{
private Task _executingTask;
private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();
/// <summary>
/// This method is called when the <see cref="IHostedService"/> starts. The implementation should return a task that represents
/// the lifetime of the long running operation(s) being performed.
/// /// </summary>
/// <param name="stoppingToken">Triggered when <see cref="IHostedService.StopAsync(CancellationToken)"/> is called.</param>
/// <returns>A <see cref="Task"/> that represents the long running operations.</returns>
protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
/// <summary>
/// Triggered when the application host is ready to start the service.
/// </summary>
/// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
public virtual Task StartAsync(CancellationToken cancellationToken)
{
// Store the task we're executing
_executingTask = ExecuteAsync(_stoppingCts.Token);
// If the task is completed then return it, this will bubble cancellation and failure to the caller
if (_executingTask.IsCompleted)
{
return _executingTask;
}
// Otherwise it's running
return Task.CompletedTask;
}
/// <summary>
/// Triggered when the application host is performing a graceful shutdown.
/// </summary>
/// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
// Stop called without start
if (_executingTask == null)
{
return;
}
try
{
// Signal cancellation to the executing method
_stoppingCts.Cancel();
}
finally
{
// Wait until the task completes or the stop token triggers
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
}
}
public virtual void Dispose()
{
_stoppingCts.Cancel();
}
}3、創(chuàng)建服務(wù)接口
創(chuàng)建一個服務(wù)接口,定義需要實現(xiàn)的任務(wù),以及對應(yīng)的實現(xiàn),如果需要執(zhí)行異步方法,記得加上 await,不然任務(wù)將不會等待執(zhí)行結(jié)果,直接進行下一個任務(wù)。
namespace ManageCore.Api
{
public interface IDemoTaskWorkService
{
/// <summary>
/// 測試任務(wù)
/// </summary>
/// <param name="stoppingToken"></param>
/// <returns></returns>
Task TaskWorkAsync(CancellationToken stoppingToken);
}
}public class DemoTaskWorkService : IDemoTaskWorkService
{
/// <summary>
/// 任務(wù)執(zhí)行
/// </summary>
/// <param name="stoppingToken"></param>
/// <returns></returns>
public async Task TaskWorkAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
//執(zhí)行任務(wù)
Console.WriteLine($"{DateTime.Now}");
//周期性任務(wù),于上次任務(wù)執(zhí)行完成后,等待5秒,執(zhí)行下一次任務(wù)
await Task.Delay(500);
}
}
}創(chuàng)建后臺服務(wù)類,繼承基類 BackgroundService,這里需要注意的是,要在 BackgroundService 中使用有作用域的服務(wù),請創(chuàng)建作用域, 默認情況下,不會為托管服務(wù)創(chuàng)建作用域,得自己管理服務(wù)的生命周期,切記!于構(gòu)造函數(shù)中注入 IServiceProvider即可。
namespace ManageCore.Api
{
public class DemoBackgroundService : BackgroundService
{
private readonly IServiceProvider _services;
public DemoBackgroundService(IServiceProvider services)
{
_services = services;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
using var scope = _services.CreateScope();
var taskWorkService = scope.ServiceProvider.GetRequiredService<IDemoTaskWorkService>();
await taskWorkService.TaskWorkAsync(stoppingToken);
}
}
}DemoBackgroundService類也是需要注冊的,注冊方式與 IHostedService 接口的方式一樣
builder.Services.AddHostedService<DemoBackgroundService>();
4、運行效果

5、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 中。
IHostedService 和 BackgroundService 區(qū)別
抽象級別
- IHostedService:需要手動實現(xiàn)啟動和停止邏輯。
- BackgroundService:通過提供具有要重寫的單個方法的基類來簡化實現(xiàn)。
使用案例
- IHostedService:適用于需要對服務(wù)生命周期進行精細控制的更復(fù)雜的方案。
- BackgroundService:非常適合受益于減少樣板代碼的更簡單、長時間運行的任務(wù)。
總結(jié)
總之.NET 8 中的 IHostedService 和 BackgroundService 提供了強大的工具集,使定時任務(wù)、后臺處理以及定期維護等功能的實現(xiàn)變得更加直接、高效和靈活。無論是構(gòu)建復(fù)雜的企業(yè)級應(yīng)用還是簡單的服務(wù)應(yīng)用,這兩個組件都能提供穩(wěn)定且高效的解決方案。
到此這篇關(guān)于.NET 8 強大功能 IHostedService 與 BackgroundService 實戰(zhàn)的文章就介紹到這了,更多相關(guān).NET 8 IHostedService 與 BackgroundService 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ASP.NET?Core中的Ocelot網(wǎng)關(guān)介紹
這篇文章介紹了ASP.NET?Core中的Ocelot網(wǎng)關(guān),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
asp.net關(guān)于Cookie跨域(域名)的問題
Cookie是一個偉大的發(fā)明,它允許Web開發(fā)者保留他們的用戶的登錄狀態(tài)。但是當(dāng)你的站點有一個以上的域名時就會出現(xiàn)問題了。在Cookie規(guī)范上說,一個cookie只能用于一個域名,不能夠發(fā)給其它的域名。因此,如果在瀏覽器中對一個域名設(shè)置了一個cookie,這個cookie對于其它的域名將無效。如果你想讓你的用戶從你的站點中的其中一個進行登錄,同時也可以在其它域名上進行登錄,這可真是一個大難題。2012-12-12
ASP.NET Core 1.0 部署 HTTPS(.NET Core 1.0)
這篇文章主要為大家詳細介紹了ASP.NET Core 1.0 部署 HTTPS(.NET Core 1.0),感興趣的小伙伴們可以參考一下2016-07-07
使用HtmlAgilityPack XPath 表達式抓取博客園數(shù)據(jù)的實現(xiàn)代碼
使用HtmlAgilityPack XPath表達式來抓取博客園數(shù)據(jù)使用WebClient 下載數(shù)據(jù),HtmlAgilityPack XPath表達式解析數(shù)據(jù),并綁定到Repeater控件2011-12-12

