實現介面
當你需要超出所提供的 BackgroundService有限控制時,你可以自行實作 IHostedService。 介面 IHostedService 是所有長期運行的 .NET 服務的基礎。 自訂實作會透過 AddHostedService<THostedService>(IServiceCollection) 擴充方法註冊。
在本教學課程中,您將瞭解如何:
- 實作 IHostedService、 和 IAsyncDisposable 介面。
- 建立一個基於計時器的服務。
- 將自訂實作使用相依性注入與日誌記錄技術註冊。
小提示
所有 「.NET 工作者」範例原始程式碼都可在 範例瀏覽器 下載。 如需詳細資訊,請參閱 瀏覽程式碼範例:在 .NET 中的工作者。
先決條件
- .NET 8.0 SDK 或更新版本
- .NET 集成開發環境 (IDE)
- 您可以隨意使用 Visual Studio
建立新專案
若要使用 Visual Studio 建立新的背景工作服務專案,請選取 [檔案]>[新增>專案...]。從 [[建立新專案] 對話框搜尋 [背景工作服務],然後選取 [背景工作服務] 範本。 如果您想要使用 .NET CLI,請在工作目錄中開啟您最愛的終端機。 執行 dotnet new 命令,並將 <Project.Name> 替換為您想要的專案名稱。
dotnet new worker --name <Project.Name>
如需 .NET CLI 新建 Worker Service 專案命令的詳細資訊,請參閱 dotnet new worker。
小提示
如果您使用 Visual Studio Code,您可以從整合式終端機執行 .NET CLI 命令。 如需詳細資訊,請參閱 Visual Studio Code:整合式終端機。
建立計時器服務
基於計時器的背景服務利用了這個 System.Threading.Timer 類別。 計時器會觸發這個 DoWork 方法。 計時器已在 IHostLifetime.StopAsync(CancellationToken) 停用,並會在處置服務容器時於 IAsyncDisposable.DisposeAsync() 上進行處置:
將模板中的內容替換 Worker 成以下 C# 程式碼,並將檔案重新命名為 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 。
將現有 Program 內容替換為以下 C# 程式碼:
using App.TimerHostedService;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<TimerService>();
IHost host = builder.Build();
host.Run();
該服務在 (Program.cs) 中以AddHostedService擴展方法註冊。 這和你註冊 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 來表示取消。
另請參閱
有幾個相關的教學可以參考:
- .NET 中的 工作者服務
- 建立佇列服務
-
在
BackgroundService中使用具有限定範圍的服務 -
使用
BackgroundService創建 Windows 服務