次の方法で共有


.NET .NET Aspire でのイベント

.NET .NET Aspireでは、イベントを使用すると、さまざまなアプリ ホストのライフ サイクル中にイベントを発行およびサブスクライブできます。 イベントは、ライフサイクル イベントよりも柔軟です。 どちらもイベント コールバック中に任意のコードを実行できますが、イベント処理では、イベントのタイミング、発行、およびカスタム イベントのサポートを細かく制御できます。

.NET .NET Aspireのイベントメカニズムは、📦Aspireの一部です。 NuGet パッケージのホスト。 このパッケージには、Aspire.Hosting.Eventing.NET アプリ ホスト プロジェクトのイベントの発行とサブスクライブに使用する、.NET Aspire 名前空間のインターフェイスとクラスのセットが用意されています。 イベントのスコープは、アプリ ホスト自体と内部のリソースです。

この記事では、.NET.NET Aspireでイベント機能を使用する方法について説明します。

アプリホストのイベント管理

次のイベントはアプリ ホストで使用でき、次の順序で発生します。

  1. BeforeStartEvent: このイベントは、アプリ ホストが起動する前に発生します。
  2. AfterEndpointsAllocatedEvent: このイベントは、アプリが割り当てられたエンドポイントをホストした後に発生します。
  3. AfterResourcesCreatedEvent: このイベントは、アプリ ホストがリソースを作成した後に発生します。

上記のすべてのイベントは、アプリ ホストのライフ サイクルに似ています。 つまり、IDistributedApplicationLifecycleHook の実装では、これらのイベントを同じように処理できます。 ただし、イベント API では、これらのイベントが発生したときに任意のコードを実行し、イベントによってカスタム イベント (IDistributedApplicationEvent インターフェイスを実装する任意のイベント) を定義できます。

アプリホストイベントに登録する

組み込みのアプリ ホスト イベントをサブスクライブするには、イベント API を使用します。 分散アプリケーション ビルダー インスタンスを作成したら、IDistributedApplicationBuilder.Eventing プロパティにアクセスし、Subscribe<T>(Func<T,CancellationToken,Task>) API を呼び出します。 次のサンプル アプリ ホスト Program.cs ファイルについて考えてみましょう。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedis("cache");

var apiService = builder.AddProject<Projects.AspireApp_ApiService>("apiservice");

builder.AddProject<Projects.AspireApp_Web>("webfrontend")
    .WithExternalHttpEndpoints()
    .WithReference(cache)
    .WaitFor(cache)
    .WithReference(apiService)
    .WaitFor(apiService);

builder.Eventing.Subscribe<ResourceEndpointsAllocatedEvent>(
    (@event, cancellationToken) =>
    {
        // The event doesn't expose an IServiceProvider, just write to the console.
        Console.WriteLine($"""
                    3. '{@event.Resource.Name}' ResourceEndpointsAllocatedEvent
            """);

        return Task.CompletedTask;
    });

builder.Eventing.Subscribe<BeforeStartEvent>(
    static (@event, cancellationToken) =>
    {
        var logger = @event.Services.GetRequiredService<ILogger<Program>>();

        logger.LogInformation("1. BeforeStartEvent");

        return Task.CompletedTask;
    });

builder.Eventing.Subscribe<AfterEndpointsAllocatedEvent>(
    static (@event, cancellationToken) =>
    {
        var logger = @event.Services.GetRequiredService<ILogger<Program>>();

        logger.LogInformation("2. AfterEndpointsAllocatedEvent");

        return Task.CompletedTask;
    });

builder.Eventing.Subscribe<AfterResourcesCreatedEvent>(
    static (@event, cancellationToken) =>
    {
        var logger = @event.Services.GetRequiredService<ILogger<Program>>();

        logger.LogInformation("4. AfterResourcesCreatedEvent");

        return Task.CompletedTask;
    });

builder.Build().Run();

上記のコードは、Subscribe API への呼び出しを追加したスターター テンプレートに基づいています。 Subscribe<T> API は、イベントのサブスクライブ解除に使用できる DistributedApplicationEventSubscription インスタンスを返します。 通常、アプリホストがシャットダウンされるとアプリ全体が破棄されるため、イベントのサブスクライブを解除する必要はないので、返されるサブスクリプションを破棄するのが一般的です。

アプリ ホストを実行すると、.NET.NET Aspire ダッシュボードが表示される時点までに、コンソールに次のログ出力が表示されます。

info: Program[0]
      1. BeforeStartEvent
info: Aspire.Hosting.DistributedApplication[0]
      Aspire version: 9.3.0-preview.1.25262.2+6d54dc081cd2e7ea435e33f7c0e62ff6946ae66d
info: Aspire.Hosting.DistributedApplication[0]
      Distributed application starting.
info: Aspire.Hosting.DistributedApplication[0]
      Application host directory is: ../AspireApp/AspireApp.AppHost
info: Program[0]
      2. AfterEndpointsAllocatedEvent
        3. 'aspire-dashboard' ResourceEndpointsAllocatedEvent
        3. 'cache' ResourceEndpointsAllocatedEvent
        3. 'apiservice' ResourceEndpointsAllocatedEvent
        3. 'webfrontend' ResourceEndpointsAllocatedEvent
info: Aspire.Hosting.DistributedApplication[0]
      Now listening on: https://localhost:17178
info: Aspire.Hosting.DistributedApplication[0]
      Login to the dashboard at https://localhost:17178/login?t=<YOUR_TOKEN>
info: Program[0]
      4. AfterResourcesCreatedEvent
info: Aspire.Hosting.DistributedApplication[0]
      Distributed application started. Press Ctrl+C to shut down.

ログ出力は、イベント ハンドラーがアプリ ホストのライフ サイクル イベントの順序で実行されることを確認します。 サブスクリプションの順序は、実行順序には影響しません。 最初に BeforeStartEvent がトリガーされ、次に AfterEndpointsAllocatedEventがトリガーされ、各リソースで ResourceEndpointsAllocatedEvent イベントが発生し、最後に AfterResourcesCreatedEventされます。

リソースイベント管理

アプリ ホスト イベントに加えて、リソース イベントをサブスクライブすることもできます。 リソース イベントは、個々のリソースに固有に発生します。 リソース イベントは、IDistributedApplicationResourceEvent インターフェイスの実装として定義されます。 次のリソース イベントは、一覧に示されている順序で使用できます。

  1. InitializeResourceEvent: オーケストレーターによって発生し、自身を初期化する必要があることをリソースに通知します。
  2. ConnectionStringAvailableEvent: 接続文字列がリソースで使用可能になったときに発生します。
  3. BeforeResourceStartedEvent: オーケストレーターが新しいリソースを開始する前にトリガーされます。
  4. ResourceReadyEvent: リソースが最初に準備完了の状態に移行したときに発生します。

リソース イベントをサブスクライブする

リソース イベントをサブスクライブするには、イベント API を使用します。 分散アプリケーション ビルダー インスタンスを作成したら、IDistributedApplicationBuilder.Eventing プロパティにアクセスし、Subscribe<T>(IResource, Func<T,CancellationToken,Task>) API を呼び出します。 次のサンプル アプリ ホスト Program.cs ファイルについて考えてみましょう。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedis("cache");

builder.Eventing.Subscribe<ResourceReadyEvent>(
    cache.Resource,
    static (@event, cancellationToken) =>
    {
        var logger = @event.Services.GetRequiredService<ILogger<Program>>();

        logger.LogInformation("4. ResourceReadyEvent");

        return Task.CompletedTask;
    });

builder.Eventing.Subscribe<InitializeResourceEvent>(cache.Resource,
    static (@event, cancellationToken) =>
    {
        var logger = @event.Services.GetRequiredService<ILogger<Program>>();

        logger.LogInformation("1. InitializeResourceEvent");

        return Task.CompletedTask;
    });

builder.Eventing.Subscribe<BeforeResourceStartedEvent>(
    cache.Resource,
    static (@event, cancellationToken) =>
    {
        var logger = @event.Services.GetRequiredService<ILogger<Program>>();

        logger.LogInformation("3. BeforeResourceStartedEvent");

        return Task.CompletedTask;
    });

builder.Eventing.Subscribe<ConnectionStringAvailableEvent>(
    cache.Resource,
    static (@event, cancellationToken) =>
    {
        var logger = @event.Services.GetRequiredService<ILogger<Program>>();

        logger.LogInformation("2. ConnectionStringAvailableEvent");

        return Task.CompletedTask;
    });

var apiService = builder.AddProject<Projects.AspireApp_ApiService>("apiservice");

builder.AddProject<Projects.AspireApp_Web>("webfrontend")
    .WithExternalHttpEndpoints()
    .WithReference(cache)
    .WaitFor(cache)
    .WithReference(apiService)
    .WaitFor(apiService);

builder.Build().Run();

上記のコードは、cache リソースのInitializeResourceEventResourceReadyEventConnectionStringAvailableEvent、およびBeforeResourceStartedEventイベントをサブスクライブします。 AddRedis が呼び出されると、IResourceBuilder<T>であるTを含むRedisResourceが返されます。 リソース ビルダーは、リソースを IResourceBuilder<T>.Resource プロパティとして公開します。 その後、対象のリソースが Subscribe API に渡され、リソース上のイベントをサブスクライブします。

アプリ ホストを実行すると、.NET.NET Aspire ダッシュボードが表示される時点までに、コンソールに次のログ出力が表示されます。

info: Aspire.Hosting.DistributedApplication[0]
      Aspire version: 9.3.0
info: Aspire.Hosting.DistributedApplication[0]
      Distributed application starting.
info: Aspire.Hosting.DistributedApplication[0]
      Application host directory is: ../AspireApp/AspireApp.AppHost
info: Program[0]
      1. InitializeResourceEvent
info: Program[0]
      2. ConnectionStringAvailableEvent
info: Program[0]
      3. BeforeResourceStartedEvent
info: Aspire.Hosting.DistributedApplication[0]
      Now listening on: https://localhost:17222
info: Aspire.Hosting.DistributedApplication[0]
      Login to the dashboard at https://localhost:17222/login?t=<YOUR_TOKEN>
info: Program[0]
      4. ResourceReadyEvent
info: Aspire.Hosting.DistributedApplication[0]
      Distributed application started. Press Ctrl+C to shut down.

手記

一部のイベントがブロックされています。 たとえば、BeforeResourceStartEvent が発行されると、特定のリソースのそのイベントのすべてのサブスクリプションの実行が完了するまで、リソースの起動はブロックされます。 イベントがブロックされているかどうかは、イベントの発行方法によって異なります (次のセクションを参照)。

イベントを発行する

いずれかの組み込みイベントをサブスクライブする場合、アプリ ホスト オーケストレーターがユーザーに代わって組み込みイベントを発行するために管理するため、イベントを自分で発行する必要はありません。 ただし、イベント API を使用してカスタム イベントを発行できます。 イベントを発行するには、まず、IDistributedApplicationEvent インターフェイスまたは IDistributedApplicationResourceEvent インターフェイスの実装としてイベントを定義する必要があります。 イベントがグローバル アプリ ホスト イベントかリソース固有のイベントかに基づいて、実装するインターフェイスを決定する必要があります。

その後、次のいずれかの API を呼び出して、イベントをサブスクライブして発行できます。

EventDispatchBehavior を指定する

イベントがディスパッチされるときに、イベントをサブスクライバーにディスパッチする方法を制御できます。 イベント ディスパッチ動作は、EventDispatchBehavior 列挙型で指定されます。 次の動作を使用できます。

既定の動作は EventDispatchBehavior.BlockingSequentialです。 この動作をオーバーライドするには、PublishAsyncなどの発行 API を呼び出すときに、必要な動作を引数として指定します。

アプリ ホストのライフ サイクル イベント

ご確認のように、イベント処理は最も柔軟なアプローチです。 ただし、このセクションでは、代替のライフサイクル イベントについて説明します。

.NET .NET Aspire アプリ ホストは、IDistributedApplicationLifecycleHook インターフェイスを実装することによってフックできるいくつかのライフ サイクルを公開します。 次のライフサイクル メソッドを使用できます。

注文 メソッド 説明
1 BeforeStartAsync 分散アプリケーションが開始される前に実行されます。
2 AfterEndpointsAllocatedAsync オーケストレーターがアプリケーション モデル内のリソースにエンドポイントを割り当てた後に実行されます。
3 AfterResourcesCreatedAsync オーケストレーターによってリソースが作成された後に実行されます。

ライフサイクル フックを登録する

ライフ サイクル フックを登録するには、IDistributedApplicationLifecycleHook インターフェイスを実装し、AddLifecycleHook API を使用してアプリ ホストにフックを登録します。

using Aspire.Hosting.Lifecycle;
using Microsoft.Extensions.Logging;

var builder = DistributedApplication.CreateBuilder(args);

builder.Services.AddLifecycleHook<LifecycleLogger>();

builder.Build().Run();

internal sealed class LifecycleLogger(ILogger<LifecycleLogger> logger)
    : IDistributedApplicationLifecycleHook
{
    public Task BeforeStartAsync(
        DistributedApplicationModel appModel, CancellationToken cancellationToken = default)
    {
        logger.LogInformation("1. BeforeStartAsync");
        return Task.CompletedTask;
    }

    public Task AfterEndpointsAllocatedAsync(
        DistributedApplicationModel appModel, CancellationToken cancellationToken = default)
    {
        logger.LogInformation("2. AfterEndpointsAllocatedAsync");
        return Task.CompletedTask;
    }

    public Task AfterResourcesCreatedAsync(
        DistributedApplicationModel appModel, CancellationToken cancellationToken = default)
    {
        logger.LogInformation("3. AfterResourcesCreatedAsync");
        return Task.CompletedTask;
    }
}

前述のコード:

  • IDistributedApplicationLifecycleHook インターフェイスを LifecycleLoggerとして実装します。
  • AddLifecycleHook API を使用して、ライフ サイクル フックをアプリ ホストに登録します。
  • すべてのイベントのメッセージをログに記録します。

このアプリ ホストを実行すると、イベントごとにライフ サイクル フックが実行されます。 次の出力が生成されます。

info: LifecycleLogger[0]
      1. BeforeStartAsync
info: Aspire.Hosting.DistributedApplication[0]
      Aspire version: 9.3.0
info: Aspire.Hosting.DistributedApplication[0]
      Distributed application starting.
info: Aspire.Hosting.DistributedApplication[0]
      Application host directory is: ../AspireApp/AspireApp.AppHost
info: LifecycleLogger[0]
      2. AfterEndpointsAllocatedAsync
info: Aspire.Hosting.DistributedApplication[0]
      Now listening on: https://localhost:17043
info: Aspire.Hosting.DistributedApplication[0]
      Login to the dashboard at https://localhost:17043/login?t=<YOUR_TOKEN>
info: LifecycleLogger[0]
      3. AfterResourcesCreatedAsync
info: Aspire.Hosting.DistributedApplication[0]
      Distributed application started. Press Ctrl+C to shut down.

アプリ ホストのライフ サイクルにフックする推奨される方法は、イベント API を使用することです。 詳細については、「 アプリ ホストのイベント」を参照してください。

こちらも参照ください