提供された BackgroundServiceを超えて有限の制御が必要な場合は、独自の IHostedServiceを実装できます。 IHostedService インターフェイスは、.NET で長時間実行されるすべてのサービスの基礎となります。 カスタム実装は、 AddHostedService<THostedService>(IServiceCollection) 拡張メソッドに登録されます。
このチュートリアルでは、以下の内容を学習します。
- IHostedServiceインターフェイスとIAsyncDisposable インターフェイスを実装します。
- タイマー ベースのサービスを作成します。
- 依存関係の挿入とログ記録を使用してカスタム実装を登録します。
ヒント
すべての ".NET のワーカー" サンプル ソース コードは、 サンプル ブラウザー でダウンロードできます。 詳細については、「コードサンプルを閲覧: .NET のワーカー」を参照してください。
[前提条件]
- .NET 8.0 SDK 以降
- .NET 統合開発環境 (IDE)
- Visual Studio を自由に使用できます
新しいプロジェクトを作成する
Visual Studio で新しい Worker Service プロジェクトを作成するには、 ファイル>New>Project...を選択します。[ 新しいプロジェクトの作成 ] ダイアログで"Worker Service" を検索し、Worker Service テンプレートを選択します。 .NET CLI を使用する場合は、作業ディレクトリでお気に入りのターミナルを開きます。
dotnet new コマンドを実行し、<Project.Name>を目的のプロジェクト名に置き換えます。
dotnet new worker --name <Project.Name>
.NET CLI の新しい worker サービス プロジェクト コマンドの詳細については、「 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;
}
}
Important
WorkerはBackgroundServiceのサブクラスでした。 これで、 TimerService は、 IHostedServiceインターフェイスと IAsyncDisposable インターフェイスの両方を実装します。
TimerServiceはsealedされ、DisposeAsync インスタンスからの_timer呼び出しがカスケードされます。 「カスケード破棄パターン」の詳細については、メソッドを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