Partilhar via


Eventos em .NET.NET Aspire

Além .NET.NET Aspire, o eventing permite que você publique e assine eventos durante vários ciclos de vida do host de aplicativos . A gestão de eventos é mais flexível do que os eventos do ciclo de vida. Ambos permitem executar código arbitrário durante retornos de chamada de eventos, mas a abordagem de eventos oferece um controlo mais preciso do agendamento e da publicação dos eventos, além de fornecer suporte para eventos personalizados.

Os mecanismos de eventos em .NET.NET Aspire fazem parte do 📦Aspire.pacote NuGet de Hospedagem. Este pacote fornece um conjunto de interfaces e classes no namespace Aspire.Hosting.Eventing que você usa para publicar e assinar eventos em seu projeto de host de aplicativo .NET.NET Aspire. A gestão de eventos está limitada ao próprio hospedeiro da aplicação e aos recursos dentro dele.

Neste artigo, irás aprender a usar os recursos de eventos no .NET.NET Aspire.

Gestão de eventos na hospedagem da aplicação

Os seguintes eventos estão disponíveis no host do aplicativo e ocorrem na seguinte ordem:

  1. BeforeStartEvent: Este evento é gerado antes do início do host do aplicativo.
  2. AfterEndpointsAllocatedEvent: Este evento é gerado depois que o host da aplicação alocou endpoints.
  3. AfterResourcesCreatedEvent: Este evento é gerado depois que o host do aplicativo criou recursos.

Todos os eventos anteriores são análogos aos ciclos de vida do host do aplicativo . Ou seja, uma implementação do IDistributedApplicationLifecycleHook poderia lidar com esses eventos da mesma forma. Com a API de eventos, no entanto, pode-se executar código arbitrário quando esses eventos são gerados e definir eventos personalizados — qualquer evento que implemente a interface IDistributedApplicationEvent.

Subscreva a eventos organizados por aplicativos

Para se inscrever nos eventos internos do host do aplicativo, use a API de eventos. Depois de ter uma instância distribuída do construtor de aplicativos, vá até a propriedade IDistributedApplicationBuilder.Eventing e chame a API Subscribe<T>(Func<T,CancellationToken,Task>). Considere o seguinte ficheiro Program.cs de um exemplo de anfitrião de aplicativo:

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<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("3. AfterResourcesCreatedEvent");

        return Task.CompletedTask;
    });

builder.Build().Run();

O código anterior é baseado no modelo inicial com a adição das chamadas à API Subscribe. A API Subscribe<T> retorna uma instância DistributedApplicationEventSubscription que você pode usar para cancelar a assinatura do evento. É comum descartar as assinaturas retornadas, pois geralmente não é necessário cancelar a assinatura de eventos, pois todo o aplicativo é desativado quando o host do aplicativo é desligado.

Quando o host do aplicativo é executado, no momento em que o painel .NET.NET Aspire é exibido, você verá a seguinte saída de log no console:

info: Program[0]
      1. BeforeStartEvent
info: Aspire.Hosting.DistributedApplication[0]
      Aspire version: 9.0.0
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
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]
      3. AfterResourcesCreatedEvent
info: Aspire.Hosting.DistributedApplication[0]
      Distributed application started. Press Ctrl+C to shut down.

A saída do log confirma que os manipuladores de eventos são executados na ordem dos eventos do ciclo de vida do host do aplicativo. A ordem de subscrição não afeta a ordem de execução. O BeforeStartEvent é acionado primeiro, seguido por AfterEndpointsAllocatedEvente, finalmente, AfterResourcesCreatedEvent.

Gestão de eventos de recursos

Além dos eventos de host do aplicativo, você também pode se inscrever em eventos de recursos. Os eventos de recurso são gerados especificamente para um recurso individual. Os eventos de recurso são definidos como implementações da interface IDistributedApplicationResourceEvent. Os seguintes eventos de recurso estão disponíveis na ordem listada:

  1. ConnectionStringAvailableEvent: Gerado quando uma string de conexão fica disponível para recurso.
  2. BeforeResourceStartedEvent: Acionado antes do orquestrador iniciar um novo recurso.
  3. ResourceReadyEvent: Acionado quando um recurso transita inicialmente para um estado de prontidão.

Inscrever-se em eventos de recursos

Para se inscrever em eventos de recursos, use a API de eventos. Depois de ter uma instância distribuída do construtor de aplicativos, vá até a propriedade IDistributedApplicationBuilder.Eventing e chame a API Subscribe<T>(IResource, Func<T,CancellationToken,Task>). Considere o seguinte arquivo de Program.cs de host de aplicativo de exemplo:

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("3. ResourceReadyEvent");

        return Task.CompletedTask;
    });

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

        logger.LogInformation("2. BeforeResourceStartedEvent");

        return Task.CompletedTask;
    });

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

        logger.LogInformation("1. 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();

O código anterior subscreve os eventos ResourceReadyEvent, ConnectionStringAvailableEvente BeforeResourceStartedEvent no recurso cache. Quando AddRedis é chamado, ele retorna um IResourceBuilder<T> onde T é um RedisResource. O construtor de recursos expõe o recurso como a propriedade IResourceBuilder<T>.Resource. O recurso em questão é então passado para a API Subscribe para assinar os eventos no recurso.

Quando o host do aplicativo é executado, no momento em que o painel .NET.NET Aspire é exibido, você verá a seguinte saída de log no console:

info: Aspire.Hosting.DistributedApplication[0]
      Aspire version: 9.0.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. ConnectionStringAvailableEvent
info: Program[0]
      2. BeforeResourceStartedEvent
info: Program[0]
      3. ResourceReadyEvent
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: Aspire.Hosting.DistributedApplication[0]
      Distributed application started. Press Ctrl+C to shut down.

Observação

Alguns eventos estão bloqueados. Por exemplo, quando o BeforeResourceStartEvent é publicado, a inicialização do recurso será bloqueada até que todas as assinaturas desse evento em um determinado recurso tenham concluído a execução. Se um evento está bloqueando ou não, depende de como ele é publicado (consulte a seção a seguir).

Publicar eventos

Ao assinar qualquer um dos eventos internos, você não precisa publicar o evento sozinho, pois o orquestrador do host do aplicativo gerencia publicar eventos internos em seu nome. No entanto, você pode publicar eventos personalizados com a API de eventos. Para publicar um evento, você precisa primeiro definir um evento como uma implementação da interface IDistributedApplicationEvent ou IDistributedApplicationResourceEvent. Você precisa determinar qual interface implementar com base em se o evento é um evento global de host de aplicativo ou um evento específico de recurso.

Em seguida, você pode se inscrever e publicar o evento chamando uma das seguintes APIs:

Forneça um EventDispatchBehavior

Quando os eventos são despachados, você pode controlar como os eventos são enviados aos assinantes. O comportamento de envio de eventos é especificado com o EventDispatchBehavior enum. Os seguintes comportamentos estão disponíveis:

O comportamento padrão é EventDispatchBehavior.BlockingSequential. Para substituir esse comportamento, ao chamar uma API de publicação, como PublishAsync, forneça o comportamento desejado como um argumento.