この記事では、.NET 6におけるIHostedServiceとBackgroundServiceの活用方法について解説します。これらのサービスを利用することで、非同期タスクをバックグラウンドで実行し、定期的なデータ取得などの処理を実装できます。本記事では具体的な実装例とコードを交えて説明します。
- 技術要件
まず、ASP.NET Coreアプリケーションを作成してデモを行います。ターミナル(ShellまたはBash)を開き、作業ディレクトリに移動して以下のコマンドを実行してMVCアプリケーションを作成します:
dotnet new mvc -n HostedServiceSample -o HostedServiceSample
Visual Studioでプロジェクトファイルをダブルクリックして開くか、VS Codeでプロジェクトを開き、既に開いているターミナルで以下のコマンドを実行します:
cd HostedServiceSample code .
- IHostedServiceの概要
ホストサービスはASP.NET Core 2.0から導入され、アプリケーションのバックグラウンドで非同期タスクを実行できます。例えば、定期的なデータ取得、バックグラウンドでの計算処理、データのクリーンアップなどに利用できます。さらに、事前設定されたメールの送信や任意のロジックの実行にも使用できます。
ホストサービスはIHostedServiceインターフェースを実装する必要があります。以下のコードに示すように:
public class SampleHostedService : IHostedService {
public Task StartAsync(CancellationToken cancellationToken) { }
public Task StopAsync(CancellationToken cancellationToken) { }
}
IHostedServiceではStartAsync()とStopAsync()メソッドを実装する必要があります。StartAsync()は実行するロジックを実装する場所で、アプリケーション起動後に一度だけ実行されます。StopAsync()メソッドはアプリケーション停止前に実行されます。つまり、スケジュールされたサービスを実装し、定期的にコードを実行するループを自分で実装する必要があります。
IHostedServiceを実行するには、ASP.NET Coreの依存性注入コンテナにシングルトンインスタンスとして登録する必要があります:
builder.Services.AddSingleton<IHostedService, SampleHostedService>();
以下の例では、ホストサービスの動作方法を示します。起動、停止、および2秒ごとにコンソールにログメッセージを書き込みます:
まず、クラスの骨格を作成し、DI経由でILoggerのインスタンスを注入します:
namespace HostedServiceSample;
public class SampleHostedService:IHostedService {
private readonly ILogger<SampleHostedService> logger;
public SampleHostedService(ILogger<SampleHostedService> logger) {
this.logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{}
public Task StopAsync(CancellationToken cancellationToken)
{}
}
次に、StopAsyncメソッドを実装します。このメソッドは接続を閉じる必要がある場合に処理するロジックです:
public Task StopAsync(CancellationToken cancellationToken)
{
logger.LogInformation("ホストサービスが停止しました……");
return Task.CompletedTask;
}
実際の作業はStartAsyncメソッド内で完了します:
public Task StartAsync(CancellationToken cancellationToken) {
logger.LogInformation("ホストサービスを開始します……");
return Task.Factory.StartNew(async () => {
while (!cancellationToken.IsCancellationRequested) {
logger.LogInformation($"ホストサービス実行中 - {DateTime.Now}");
try{
//2秒待機
await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
}catch (OperationCanceledException) { }
}
}, cancellationToken);
}
次に実行してテストしてみましょう。以下のコマンドを実行します:
dotnet run
- BackgroundServiceの概要
BackgroundServiceクラスはASP.NET Core 3.0で導入されました。これはIHostedServiceインターフェースを実装する抽象クラスで、ExecuteAsyncという抽象メソッドを提供し、このメソッドはTaskを返します。
上記の例のホストサービスを書き換えてみましょう。まず以下のようにクラスの骨格を作成します:
namespace HostedServiceSample;
public class SampleBackgroundService : BackgroundService {
private readonly ILogger<SampleBackgroundService> logger;
public SampleBackgroundService(ILogger<SampleBackgroundService> logger){
this.logger = logger;
}
}
次にStopAsyncメソッドをオーバーライドします:
public override async Task StopAsync(CancellationToken cancellationToken) {
logger.LogInformation("バックグラウンドサービスが停止しました……");
await Task.CompletedTask;
}
最後にExecuteAsyncメソッドをオーバーライドします:
protected override async Task ExecuteAsync(CancellationToken cancellationToken) {
logger.LogInformation("バックグラウンドサービスを開始します……");
await Task.Factory.StartNew(async () =>{
while(!cancellationToken.IsCancellationRequested) {
logger.LogInformation($"バックグラウンドサービス実行中 - {DateTime.Now}");
try{
await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
}catch (OperationCanceledException) {}
}
}, cancellationToken);
}
登録も書き直します。ASP.NET Core 3.0以降では、ServiceCollectionにホストサービスまたはバックグラウンドワーカーを登録する新しい拡張メソッドがあります:
builder.Services.AddHostedService<SampleBackgroundService>();
ターミナルで以下のコマンドを実行してアプリケーションをテストします:
dotnet run
- Worker Serviceの概要
Worker Serviceは「ワーカー」または「ワーカーサービス」とも呼ばれます。
ASP.NET Core 3.0以降では、シンプルなワーカーサービスの作成が非常に容易になりました。このサービスはWebサーバー外でもホストできます。
新しいプロジェクトを作成してみましょう:
dotnet new worker -n BackgroundServiceSample -o BackgroundServiceSample
このコマンドはProgram.csとWorker.csを含むコンソールアプリケーションを作成します。Worker.csにはWorkerクラスが含まれており、これはBackgroundServiceクラスから継承されています。ASP.NET 5.0以前では、Program.csファイルは以前のバージョンに似ていますが、WebHostBuilderがありません:
public class Program {
public static void Main(string[] args){
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)=>
Host.CreateDefaultBuilder(args).ConfigureServices((hostContext, services) =>{
services.AddHostedService<Worker>();
});
}
ASP.NET Core 6.0では、Program.csはミニAPIと同様に簡素化されています。以下のようになります:
using BackgroundServiceSample;
IHost host = Host.CreateDefaultBuilder(args).ConfigureServices(services =>{
services.AddHostedService<Worker>();
}).Build();
await host.RunAsync();
ここではIHostを作成し、依存性注入を有効にしています。依存性注入は任意の.NET Coreアプリケーションで使用でき、ASP.NET Coreアプリケーションに限定されません。
次に、ワーカーをサービスコレクションに追加します。これにより、サービスはWindowsサービスとして、またはDockerコンテナ内のバックグラウンドプロセスとして実行できます。