Udostępnij za pośrednictwem


Zdarzenia w .NET.NET Aspire

W .NET.NET Aspire, mechanizm obsługi zdarzeń umożliwia publikowanie i subskrybowanie zdarzeń podczas różnych cykli życia środowiska uruchomieniowego aplikacji . System eventowy jest bardziej elastyczny niż zdarzenia cyklu życia. Obie umożliwiają uruchamianie dowolnego kodu podczas wywołań zwrotnych zdarzeń, ale obsługa zdarzeń zapewnia dokładnszą kontrolę nad chronometrażem, publikowaniem i zapewnia obsługę zdarzeń niestandardowych.

Mechanizmy zdarzeń w .NET.NET Aspire są częścią 📦Aspirepakietu NuGet Hosting. Ten pakiet zawiera zestaw interfejsów i klas w przestrzeni nazw Aspire.Hosting.Eventing używanej do publikowania i subskrybowania zdarzeń w projekcie hosta aplikacji .NET.NET Aspire. Zdarzenie jest ograniczone do samego hosta aplikacji i zasobów w tym zakresie.

Z tego artykułu dowiesz się, jak używać funkcji zdarzeń w programie .NET.NET Aspire.

Zdarzenia hosta aplikacji

Następujące zdarzenia są dostępne na hoście aplikacji i występują w następującej kolejności:

  1. BeforeStartEvent: to zdarzenie jest wywoływane przed uruchomieniem hosta aplikacji.
  2. AfterEndpointsAllocatedEvent: To zdarzenie jest generowane po przydzieleniu punktów końcowych przez hosta aplikacji.
  3. AfterResourcesCreatedEvent: To zdarzenie jest zgłaszane po utworzeniu zasobów przez hosta aplikacji.

Wszystkie powyższe zdarzenia są podobne do cykli życia hosta aplikacji . Oznacza to, że implementacja IDistributedApplicationLifecycleHook może obsługiwać te zdarzenia tak samo. Za pomocą interfejsu API zdarzeń można jednak uruchomić dowolny kod po wystąpieniu tych zdarzeń, a także definiować zdarzenia niestandardowe — dowolne zdarzenie implementujące interfejs IDistributedApplicationEvent.

Zapisz się na wydarzenia hosta aplikacji

Aby zasubskrybować wbudowane zdarzenia hosta aplikacji, użyj API obsługi zdarzeń. Po utworzeniu wystąpienia konstruktora aplikacji w środowisku rozproszonym przejdź do właściwości IDistributedApplicationBuilder.Eventing i wywołaj API Subscribe<T>(Func<T,CancellationToken,Task>). Rozważmy następujący przykładowy plik Program.cs hosta aplikacji:

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();

Powyższy kod jest oparty na szablonie początkowym z dodawaniem wywołań do interfejsu API Subscribe. Interfejs API Subscribe<T> zwraca wystąpienie DistributedApplicationEventSubscription, którego można użyć do wyrejestrowania się z wydarzenia. Często odrzucane są zwrócone subskrypcje, jako że nie trzeba zwykle anulować subskrypcji zdarzeń, ponieważ cała aplikacja jest zamykana po wyłączeniu hosta aplikacji.

Po uruchomieniu hosta aplikacji, w momencie gdy wyświetlany jest pulpit nawigacyjny .NET.NET Aspire, w konsoli powinny pojawić się następujące dane wyjściowe dziennika:

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.

Dane wyjściowe dziennika potwierdzają, że programy obsługi zdarzeń są wykonywane w kolejności zdarzeń cyklu życia hosta aplikacji. Kolejność subskrypcji nie ma wpływu na kolejność wykonywania. Najpierw zostanie wyzwolony BeforeStartEvent, a następnie AfterEndpointsAllocatedEvent, a na koniec AfterResourcesCreatedEvent.

Obsługa zdarzeń zasobów

Oprócz zdarzeń hosta aplikacji można również subskrybować zdarzenia dotyczące zasobów. Zdarzenia zasobów są zgłaszane w odniesieniu do pojedynczego zasobu. Zdarzenia zasobów są definiowane jako implementacje interfejsu IDistributedApplicationResourceEvent. Następujące zdarzenia zasobów są dostępne w podanej kolejności:

  1. ConnectionStringAvailableEvent: Zgłaszane, gdy łańcuch połączenia staje się dostępny dla zasobu.
  2. BeforeResourceStartedEvent: podniesiony przed uruchomieniem nowego zasobu przez orkiestratora.
  3. ResourceReadyEvent: zgłaszane, gdy zasób początkowo przechodzi do stanu gotowego.

Subskrybowanie zdarzeń zasobów

Aby subskrybować zdarzenia zasobów, użyj API zdarzeń. Po utworzeniu instancji rozproszonego narzędzia do tworzenia aplikacji przejdź do właściwości IDistributedApplicationBuilder.Eventing i wywołaj API Subscribe<T>(IResource, Func<T,CancellationToken,Task>). Rozważmy następujący przykładowy plik Program.cs hosta aplikacji:

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();

Powyższy kod subskrybuje zdarzenia ResourceReadyEvent, ConnectionStringAvailableEventi BeforeResourceStartedEvent w zasobie cache. Po wywołaniu AddRedis, zwraca IResourceBuilder<T>, gdzie T jest RedisResource. Konstruktor zasobów uwidacznia zasób jako właściwość IResourceBuilder<T>.Resource. Zasób, o którym mowa, jest następnie przekazywany do interfejsu API Subscribe w celu subskrybowania zdarzeń na zasobie.

Gdy host aplikacji zostanie uruchomiony, do czasu wyświetlenia pulpitu nawigacyjnego .NET.NET Aspire, w konsoli powinny pojawić się następujące logi:

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.

Notatka

Niektóre zdarzenia są blokujące. Na przykład po opublikowaniu BeforeResourceStartEvent uruchomienie zasobu zostanie zablokowane do momentu zakończenia wykonywania wszystkich subskrypcji dla tego zdarzenia w danym zasobie. To, czy zdarzenie jest blokujące, zależy od sposobu jego opublikowania (patrz kolejna sekcja).

Publikowanie zdarzeń

Podczas subskrybowania dowolnego z wbudowanych zdarzeń nie musisz publikować zdarzenia samodzielnie, ponieważ orkiestrator hosta aplikacji zarządza publikowaniem wbudowanych zdarzeń w Twoim imieniu. Można jednak publikować zdarzenia niestandardowe za pomocą interfejsu API zdarzeń. Aby opublikować zdarzenie, należy najpierw zdefiniować zdarzenie jako implementację interfejsu IDistributedApplicationEvent lub IDistributedApplicationResourceEvent. Należy określić interfejs do zaimplementowania na podstawie tego, czy zdarzenie jest zdarzeniem hosta aplikacji globalnej, czy zdarzeniem specyficznym dla zasobu.

Następnie możesz subskrybować i publikować zdarzenie, wywołując jeden z następujących interfejsów API:

Podaj EventDispatchBehavior

Po wysłaniu zdarzeń można kontrolować sposób wysyłania zdarzeń do subskrybentów. Zachowanie wysyłania zdarzeń jest określane przy użyciu wyliczenia EventDispatchBehavior. Dostępne są następujące zachowania:

Domyślne zachowanie to EventDispatchBehavior.BlockingSequential. Aby zastąpić to zachowanie, podczas wywoływania interfejsu API publikowania, takiego jak PublishAsync, podaj żądane zachowanie jako argument.