實作 IHostedService
介面
當您需要 BackgroundService 以外的有限控制項時,您可以實作自己的 IHostedService。 IHostedService 介面是 .NET 中所有長時間執行之服務的基礎。 自訂實作會以 AddHostedService<THostedService>(IServiceCollection) 擴充方法註冊。
在本教學課程中,您會了解如何:
- 實作 IHostedService 和 IAsyncDisposable 介面。
- 建立以計時器為基礎的服務。
- 使用相依性插入和記錄來註冊自訂實作。
提示
所有「.NET 中的背景工作角色」範例原始程式碼都可在 [範例瀏覽器] 中下載。 如需詳細資訊,請參閱瀏覽程式碼範例:.NET 中的背景工作角色。
必要條件
- .NET 8.0 SDK 或更新版本
- .NET 整合式開發環境 (IDE)
- 歡迎使用 Visual Studio
建立新專案
若要使用 Visual Studio Code 建立新的背景工作服務專案,您將選取 [檔案]>[新增]>[專案...]。從 [建立新專案] 對話方塊搜尋 [背景工作服務],然後選取 [背景工作服務] 範本。 如果您想要使用 .NET CLI,請在工作目錄中開啟您慣用的終端。 執行 dotnet new
命令,並以您想要的專案名稱取代 <Project.Name>
。
dotnet new worker --name <Project.Name>
如需 .NET CLI 新背景工作服務專案命令的詳細資訊,請參閱 dotnet new worker。
提示
如果您使用 Visual Studio Code,您可以從整合式終端執行 .NET CLI 命令。 如需詳細資訊,請參閱 Visual Studio Code:整合式終端。
建立計時器服務
計時器型背景服務會使用 System.Threading.Timer 類別。 計時器會觸發 DoWork
方法。 計時器已在 IHostLifetime.StopAsync(CancellationToken) 停用,並會在處置服務容器時於 IAsyncDisposable.DisposeAsync() 上進行處置:
以下列 C# 程式碼取代範本中 Worker
的內容,並將檔案重新命名為 TimerService.cs:
namespace App.TimerHostedService;
public sealed class TimerService(ILogger<TimerService> logger) : IHostedService, IAsyncDisposable
{
private readonly Task _completedTask = Task.CompletedTask;
private int _executionCount = 0;
private Timer? _timer;
public Task StartAsync(CancellationToken stoppingToken)
{
logger.LogInformation("{Service} is running.", nameof(TimerHostedService));
_timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
return _completedTask;
}
private void DoWork(object? state)
{
int count = Interlocked.Increment(ref _executionCount);
logger.LogInformation(
"{Service} is working, execution count: {Count:#,0}",
nameof(TimerHostedService),
count);
}
public Task StopAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Service} is stopping.", nameof(TimerHostedService));
_timer?.Change(Timeout.Infinite, 0);
return _completedTask;
}
public async ValueTask DisposeAsync()
{
if (_timer is IAsyncDisposable timer)
{
await timer.DisposeAsync();
}
_timer = null;
}
}
重要
Worker
為 BackgroundService 的子類別。 現在,TimerService
會同時實作 IHostedService 和 IAsyncDisposable 介面。
TimerService
會 sealed
並從其 _timer
執行個體串聯 DisposeAsync
呼叫。 如需有關「串聯處置模式」的詳細資訊,請參閱實作 DisposeAsync
方法。
呼叫 StartAsync 時,計時器會具現化而因此啟動。
提示
Timer 不會等先前的執行 DoWork
完成,因此此處說明的方法可能不適用於每個狀況。 Interlocked.Increment 可將執行計數器作為不可部分完成的作業進行遞增,以確保多個執行緒不會同時更新 _executionCount
。
使用下列 C# 程式碼取代目前 Program
的內容:
using App.TimerHostedService;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<TimerService>();
IHost host = builder.Build();
host.Run();
此服務以 AddHostedService
擴充方法註冊於 (Program.cs)。 這個方法與註冊 BackgroundService 子類別時所使用的擴充方法相同,因為它們都會實作 IHostedService 介面。
如需註冊服務的詳細資訊,請參閱 .NET 中的相依性插入。
驗證服務功能
若要從 Visual Studio 執行應用程式,請選取 F5 或選取 [偵錯]> [開始偵錯] 功能表選項。 如果您使用的是 .NET CLI,請從工作目錄執行 dotnet run
命令:
dotnet run
如需 .NET CLI 執行命令的詳細資訊,請參閱 dotnet run。
讓應用程式執行一段時間以產生數個執行計數增量。 您會看到類似下方的輸出:
info: App.TimerHostedService.TimerService[0]
TimerHostedService is running.
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: .\timer-service
info: App.TimerHostedService.TimerService[0]
TimerHostedService is working, execution count: 1
info: App.TimerHostedService.TimerService[0]
TimerHostedService is working, execution count: 2
info: App.TimerHostedService.TimerService[0]
TimerHostedService is working, execution count: 3
info: App.TimerHostedService.TimerService[0]
TimerHostedService is working, execution count: 4
info: Microsoft.Hosting.Lifetime[0]
Application is shutting down...
info: App.TimerHostedService.TimerService[0]
TimerHostedService is stopping.
如果從 Visual Studio 內執行應用程式,請選取 [偵錯]>[停止偵錯...]。或者,從主控台視窗選取 Ctrl + C 以發出取消訊號。
另請參閱
您可以考慮幾個相關的教學課程: