Organizzazione di eventi in .NET.NET Aspire
In .NET.NET Aspire, l'eventing consente di pubblicare e sottoscrivere eventi durante i diversi cicli di vita dell'host dell'applicazione . Il sistema di eventi è più flessibile rispetto agli eventi del ciclo di vita. Entrambi consentono di eseguire codice arbitrario durante i callback degli eventi, ma l'eventing offre un controllo più preciso della tempistica degli eventi, della pubblicazione e supporta eventi personalizzati.
I meccanismi di gestione degli eventi in .NET.NET Aspire fanno parte del pacchetto NuGet 📦Aspire.Hosting. Questo pacchetto fornisce un set di interfacce e classi nello spazio dei nomi Aspire.Hosting.Eventing che si usano per pubblicare e abbonarsi agli eventi nel progetto host dell'app .NET.NET Aspire. La gestione degli eventi è limitata all'host dell'app stesso e alle risorse all'interno dell'app.
Questo articolo illustra come usare le funzionalità di gestione degli eventi in .NET.NET Aspire.
Eventi di hosting dell'app
Gli eventi seguenti sono disponibili nell'host dell'app e si verificano nell'ordine seguente:
- BeforeStartEvent: questo evento viene generato prima dell'avvio dell'host dell'app.
- AfterEndpointsAllocatedEvent: Questo evento viene generato dopo che l'host dell'app ha allocato gli endpoint.
- AfterResourcesCreatedEvent: Questo evento viene generato dopo la creazione delle risorse dell'host dell'app.
Tutti gli eventi precedenti sono analoghi ai cicli di vita dell'host dell'app . Ovvero, un'implementazione del IDistributedApplicationLifecycleHook potrebbe gestire questi eventi allo stesso modo. Con l'API di eventi, tuttavia, è possibile eseguire codice arbitrario quando questi eventi vengono attivati e definire eventi personalizzati, qualsiasi evento che implementa l'interfaccia IDistributedApplicationEvent.
Sottoscrivere gli eventi host dell'app
Per sottoscrivere gli eventi host dell'app predefiniti, usare l'API di creazione di eventi. Dopo aver creato un'istanza di Generatore di applicazioni distribuite, andare alla proprietà IDistributedApplicationBuilder.Eventing e chiamare l'API Subscribe<T>(Func<T,CancellationToken,Task>). Si consideri il file di host dell'app di esempio seguente 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<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();
Il codice precedente si basa sul modello di avvio con l'aggiunta delle chiamate all'API Subscribe
. L'API Subscribe<T>
restituisce un'istanza di DistributedApplicationEventSubscription che è possibile usare per annullare la sottoscrizione all'evento. È comune scartare le sottoscrizioni restituite, poiché in genere non è necessario annullare la sottoscrizione agli eventi, dato che l'intera app viene chiusa quando l'host dell'app viene arrestato.
Non appena l'host dell'app viene eseguito e il dashboard .NET.NET Aspire viene visualizzato, nella console si dovrebbe vedere il seguente output del log:
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.
L'output del log conferma che i gestori degli eventi vengono eseguiti nell'ordine degli eventi del ciclo di vita dell'host dell'app. L'ordine di sottoscrizione non influisce sull'ordine di esecuzione. Il BeforeStartEvent
viene attivato per primo, seguito da AfterEndpointsAllocatedEvent
e infine AfterResourcesCreatedEvent
.
Eventi delle risorse
Oltre agli eventi host dell'applicazione, è anche possibile abbonarsi agli eventi delle risorse. Gli eventi delle risorse vengono generati specificamente per una singola risorsa. Gli eventi delle risorse vengono definiti come implementazioni dell'interfaccia IDistributedApplicationResourceEvent. Gli eventi di risorsa seguenti sono disponibili nell'ordine elencato:
- ConnectionStringAvailableEvent: Attivato quando una stringa di connessione è disponibile per una risorsa.
- BeforeResourceStartedEvent: generato prima che l'orchestratore avvii una nuova risorsa.
- ResourceReadyEvent: Sollevato quando una risorsa passa per la prima volta a uno stato pronto.
Iscriversi agli eventi delle risorse
Per iscriversi agli eventi delle risorse, usare l'API di eventi. Dopo aver creato un'istanza di costruttore di applicazioni distribuite, accedi alla proprietà IDistributedApplicationBuilder.Eventing e chiama l'API Subscribe<T>(IResource, Func<T,CancellationToken,Task>). Si consideri il file di host dell'app di esempio seguente 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("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();
Il codice precedente sottoscrive gli eventi ResourceReadyEvent
, ConnectionStringAvailableEvent
e BeforeResourceStartedEvent
nella risorsa cache
. Quando viene chiamato AddRedis, restituisce un IResourceBuilder<T> in cui T
è un RedisResource. Il generatore di risorse espone la risorsa come proprietà IResourceBuilder<T>.Resource. La risorsa in questione viene quindi passata all'API Subscribe
per sottoscrivere gli eventi nella risorsa.
Quando l'host dell'app viene eseguito, entro il momento in cui viene visualizzato il dashboard .NET.NET Aspire, dovresti vedere il seguente output del log nella 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.
Nota
Alcuni eventi sono bloccanti. Ad esempio, quando il BeforeResourceStartEvent
viene pubblicato, l'avvio della risorsa verrà bloccato fino a quando tutte le sottoscrizioni per tale evento su una risorsa specifica abbiano completato l'esecuzione. Il blocco o meno di un evento dipende dalla modalità di pubblicazione (vedere la sezione seguente).
Pubblicare eventi
Quando si sottoscrive uno degli eventi predefiniti, non è necessario pubblicare l'evento manualmente perché l'agente di orchestrazione host dell'app gestisce la pubblicazione di eventi predefiniti per conto dell'utente. Tuttavia, è possibile pubblicare eventi personalizzati con l'API di eventi. Per pubblicare un evento, è necessario innanzitutto definire un evento come implementazione dell'interfaccia IDistributedApplicationEvent o IDistributedApplicationResourceEvent. È necessario determinare l'interfaccia da implementare in base al tipo di evento, se si tratta di un evento host globale dell'app o di un evento specifico della risorsa.
È quindi possibile sottoscrivere e pubblicare l'evento chiamando una delle API seguenti:
- PublishAsync<T>(T, CancellationToken): pubblica un evento per tutti i sottoscrittori del tipo di evento specifico.
- PublishAsync<T>(T, EventDispatchBehavior, CancellationToken): pubblica un evento per tutti i sottoscrittori del tipo di evento specifico con un comportamento di invio specificato.
Fornire un EventDispatchBehavior
Quando gli eventi vengono inviati, è possibile controllare il modo in cui gli eventi vengono inviati ai sottoscrittori. Il comportamento di invio dell'evento viene specificato con l'enumerazione EventDispatchBehavior
. Sono disponibili i comportamenti seguenti:
- EventDispatchBehavior.BlockingSequential: attiva eventi in sequenza e blocca fino a quando non sono stati elaborati tutti.
- EventDispatchBehavior.BlockingConcurrent: genera eventi simultaneamente e blocca fino a quando non vengono elaborati tutti.
- EventDispatchBehavior.NonBlockingSequential: attiva eventi in sequenza ma non blocca.
- EventDispatchBehavior.NonBlockingConcurrent: Attiva eventi in parallelo ma non blocca.
Il comportamento predefinito è EventDispatchBehavior.BlockingSequential
. Per eseguire l'override di questo comportamento, quando si chiama un'API di pubblicazione, ad esempio PublishAsync, specificare il comportamento desiderato come argomento.