Host ogólny platformy .NET

Szablony usługi Worker Service tworzą ogólny host platformy .NET, HostBuilder. Host ogólny może być używany z innymi typami aplikacji platformy .NET, takimi jak aplikacje konsolowe.

Host to obiekt, który hermetyzuje zasoby aplikacji i funkcje okresu istnienia, takie jak:

  • Wstrzykiwanie zależności (DI)
  • Rejestrowanie
  • Konfiguracja
  • Zamykanie aplikacji
  • IHostedService Implementacje

Po uruchomieniu hosta wywołuje IHostedService.StartAsync każdą implementację zarejestrowaną IHostedService w kolekcji hostowanych usług kontenera usługi. W aplikacji usługi procesu roboczego wszystkie IHostedService implementacje zawierające BackgroundService wystąpienia mają BackgroundService.ExecuteAsync wywoływane metody.

Głównym powodem włączenia wszystkich współzależnych zasobów aplikacji w jednym obiekcie jest zarządzanie okresem istnienia: kontrola nad uruchamianiem aplikacji i bezproblemowym zamykaniem. Jest to realizowane za pomocą pakietu NuGet Microsoft.Extensions.Hosting.

Konfigurowanie hosta

Host jest zwykle konfigurowany, kompilowany i uruchamiany przez kod w Program klasie . Metoda Main :

Szablony usługi procesów roboczych platformy .NET generują następujący kod, aby utworzyć hosta ogólnego:

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((hostContext, services) =>
    {
        services.AddHostedService<Worker>();
    })
    .Build();

host.Run();

Domyślne ustawienia konstruktora

Metoda CreateDefaultBuilder :

  • Ustawia katalog główny zawartości na ścieżkę zwróconą przez GetCurrentDirectory().
  • Ładuje konfigurację hosta z:
    • Zmienne środowiskowe poprzedzone prefiksem DOTNET_.
    • Argumenty wiersza polecenia.
  • Ładuje konfigurację aplikacji z:
    • appsettings.json.
    • Appsettings. {Environment}.json.
    • Secret Manager, gdy aplikacja działa w Development środowisku.
    • Zmienne środowiskowe.
    • Argumenty wiersza polecenia.
  • Dodaje następujących dostawców rejestrowania:
    • Konsola
    • Debugowanie
    • EventSource
    • EventLog (tylko w przypadku uruchamiania w Windows)
  • Włącza walidację zakresu i walidację zależności , gdy środowisko ma wartość Development.

Metoda ConfigureServices uwidacznia możliwość dodawania usług do Microsoft.Extensions.DependencyInjection.IServiceCollection wystąpienia. Później te usługi można udostępnić z iniekcji zależności.

Usługi dostarczane przez platformę

Następujące usługi są rejestrowane automatycznie:

IHostApplicationLifetime

Wstrzykuj usługę IHostApplicationLifetime do dowolnej klasy, aby obsługiwać zadania po uruchomieniu i bezproblemowym zamykaniu. Trzy właściwości interfejsu to tokeny anulowania używane do rejestrowania metod uruchamiania aplikacji i procedury obsługi zdarzeń zatrzymania aplikacji. Interfejs zawiera również metodę StopApplication() .

Poniższy przykład to implementacja IHostedService rejestrujący IHostApplicationLifetime zdarzenia:

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace AppLifetime.Example;

public sealed class ExampleHostedService : IHostedService
{
    private readonly ILogger _logger;

    public ExampleHostedService(
        ILogger<ExampleHostedService> logger,
        IHostApplicationLifetime appLifetime)
    {
        _logger = logger;

        appLifetime.ApplicationStarted.Register(OnStarted);
        appLifetime.ApplicationStopping.Register(OnStopping);
        appLifetime.ApplicationStopped.Register(OnStopped);
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("1. StartAsync has been called.");

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("4. StopAsync has been called.");

        return Task.CompletedTask;
    }

    private void OnStarted()
    {
        _logger.LogInformation("2. OnStarted has been called.");
    }

    private void OnStopping()
    {
        _logger.LogInformation("3. OnStopping has been called.");
    }

    private void OnStopped()
    {
        _logger.LogInformation("5. OnStopped has been called.");
    }
}

Szablon usługi Worker Service można zmodyfikować w celu dodania implementacji ExampleHostedService :

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using AppLifetime.Example;

using IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((_, services) =>
        services.AddHostedService<ExampleHostedService>())
    .Build();

await host.RunAsync();

Aplikacja napisze następujące przykładowe dane wyjściowe:

// Sample output:
//     info: ExampleHostedService[0]
//           1. StartAsync has been called.
//     info: ExampleHostedService[0]
//           2. OnStarted has been called.
//     info: Microsoft.Hosting.Lifetime[0]
//           Application started.Press Ctrl+C to shut down.
//     info: Microsoft.Hosting.Lifetime[0]
//           Hosting environment: Production
//     info: Microsoft.Hosting.Lifetime[0]
//           Content root path: ..\app-lifetime\bin\Debug\net6.0
//     info: ExampleHostedService[0]
//           3. OnStopping has been called.
//     info: Microsoft.Hosting.Lifetime[0]
//           Application is shutting down...
//     info: ExampleHostedService[0]
//           4. StopAsync has been called.
//     info: ExampleHostedService[0]
//           5. OnStopped has been called.

IHostLifetime

Implementacja IHostLifetime kontroluje czas uruchamiania i zatrzymywania hosta. Używana jest ostatnia zarejestrowana implementacja. Microsoft.Extensions.Hosting.Internal.ConsoleLifetime to domyślna IHostLifetime implementacja. Aby uzyskać więcej informacji na temat mechaniki okresu istnienia zamykania, zobacz Zamykanie hosta.

IHostEnvironment

Wstrzykiwanie IHostEnvironment usługi do klasy w celu uzyskania informacji o następujących ustawieniach:

Konfiguracja hosta

Konfiguracja hosta służy do konfigurowania właściwości implementacji IHostEnvironment .

Konfiguracja hosta jest dostępna w pliku HostBuilderContext.Configuration w metodzie ConfigureAppConfiguration . Podczas wywoływania ConfigureAppConfiguration metody element HostBuilderContext i IConfigurationBuilder jest przekazywany do metody configureDelegate. Element configureDelegate jest zdefiniowany jako .Action<HostBuilderContext, IConfigurationBuilder> Kontekst konstruktora hosta uwidacznia Configuration właściwość , która jest wystąpieniem IConfigurationklasy . Reprezentuje on konfigurację utworzoną na podstawie hosta, natomiast IConfigurationBuilder obiekt jest obiektem konstruktora używanym do konfigurowania aplikacji.

Porada

Po ConfigureAppConfiguration wywołaniu HostBuilderContext.Configuration metody jest zastępowana konfiguracją aplikacji.

Aby dodać konfigurację hosta, wywołaj metodę ConfigureHostConfiguration na IHostBuilder. ConfigureHostConfiguration można wywołać wiele razy za pomocą wyników addytywnego. Host używa niezależnie od tego, która opcja ustawia wartość jako ostatnią dla danego klucza.

Poniższy przykład tworzy konfigurację hosta:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;

using IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureHostConfiguration(configHost =>
    {
        configHost.SetBasePath(Directory.GetCurrentDirectory());
        configHost.AddJsonFile("hostsettings.json", optional: true);
        configHost.AddEnvironmentVariables(prefix: "PREFIX_");
        configHost.AddCommandLine(args);
    })
    .Build();

// Application code should start here.

await host.RunAsync();

Konfiguracja aplikacji

Konfiguracja aplikacji jest tworzona przez wywołanie ConfigureAppConfiguration metody .IHostBuilder ConfigureAppConfiguration można wywołać wiele razy za pomocą wyników addytywnego. Aplikacja używa dowolnej opcji ustawia ostatnią wartość dla danego klucza.

Konfiguracja utworzona przez ConfigureAppConfiguration jest dostępna w pliku HostBuilderContext.Configuration dla kolejnych operacji i jako usługi z di. Konfiguracja hosta jest również dodawana do konfiguracji aplikacji.

Aby uzyskać więcej informacji, zobacz Konfiguracja na platformie .NET.

Zamykanie hosta

Proces hostowanej usługi można zatrzymać w następujący sposób:

Wszystkie te scenariusze nie są obsługiwane bezpośrednio przez kod hostingu. Właściciel procesu musi radzić sobie z nimi tak samo jak każda aplikacja. Istnieje kilka dodatkowych sposobów zatrzymania hostowanego procesu usługi:

  • Jeśli ConsoleLifetime jest używany, nasłuchuje następujących sygnałów i próbuje zatrzymać hosta bezpiecznie.
    • SIGINT (lub CTRL+C).
    • SIGQUIT (lub CTRL+BREAK w Windows, CTRL+\ w systemie Unix).
    • SIGTERM (wysyłane przez inne aplikacje, takie jak docker stop).
  • Jeśli aplikacja wywołuje metodę Environment.Exit.

Te scenariusze są obsługiwane przez wbudowaną logikę hostingu, w szczególności klasę ConsoleLifetime . ConsoleLifetime próbuje obsłużyć sygnały "zamykania" SIGINT, SIGQUIT i SIGTERM, aby umożliwić bezproblemowe wyjście z aplikacji.

Przed platformą .NET 6 nie było możliwości bezproblemowego obsługi kodu platformy .NET. Aby obejść to ograniczenie, ConsoleLifetime należy zasubskrybować usługę System.AppDomain.ProcessExit. Gdy ProcessExit został zgłoszony, ConsoleLifetime zasygnalizuje, że host zatrzyma i zablokuje ProcessExit wątek, czekając na zatrzymanie hosta. Pozwoliłoby to na uruchomienie kodu oczyszczania w aplikacji — na przykład IHost.StopAsync i kodu po HostingAbstractionsHostExtensions.Run metodzie Main .

Spowodowało to inne problemy, ponieważ SIGTERM nie był jedynym sposobem, w jaki ProcessExit został podniesiony. Jest on również wywoływany przez kod w aplikacji wywołującej Environment.Exitelement . Environment.Exit nie jest wdzięknym sposobem zamykania procesu w Microsoft.Extensions.Hosting modelu aplikacji. ProcessExit Zgłasza zdarzenie, a następnie kończy proces. Main Koniec metody nie jest wykonywany. Wątki tła i pierwszego planu są przerywane, a finally bloki nie są wykonywane.

Ponieważ ConsoleLifetime zablokowano ProcessExit podczas oczekiwania na zamknięcie hosta, to zachowanie doprowadziło również do zakleszczenia z Environment.Exit bloków oczekujących na wywołanie do ProcessExit. Ponadto, ponieważ obsługa SIGTERM próbowała bezpiecznie zamknąć proces, ConsoleLifetime ustawi ExitCode wartość 0, która sklonowała kod zakończenia użytkownika przekazany do Environment.Exitelementu .

W programie .NET 6 sygnały POSIX są obsługiwane i obsługiwane. ConsoleLifetime Dzięki temu można bezpiecznie obsługiwać metodę SIGTERM i nie angażować się już wtedy, gdy Environment.Exit jest wywoływana.

Porada

W przypadku platformy .NET 6 lub nowszej ConsoleLifetime nie ma już logiki do obsługi scenariusza Environment.Exit. Aplikacje wywołujące Environment.Exit logikę czyszczenia i wymagające wykonania logiki czyszczenia mogą subskrybować ProcessExit się samodzielnie. Hosting nie będzie już próbował bezpiecznie zatrzymać hosta w tym scenariuszu.

Jeśli aplikacja korzysta z hostingu i chcesz bezpiecznie zatrzymać hosta, możesz wywołać IHostApplicationLifetime.StopApplication metodę zamiast Environment.Exit.

Proces zamykania hostingu

Na poniższym diagramie sekwencji pokazano, jak sygnały są obsługiwane wewnętrznie w kodzie hostingu. Większość użytkowników nie musi rozumieć tego procesu. Jednak w przypadku deweloperów, którzy potrzebują głębokiego zrozumienia, może to pomóc w rozpoczęciu pracy.

Po uruchomieniu hosta, gdy użytkownik wywołuje Run program lub WaitForShutdown, program obsługi zostanie zarejestrowany dla IApplicationLifetime.ApplicationStoppingprogramu . Wykonanie jest wstrzymane w WaitForShutdownprogramie , czekając na ApplicationStopping podniesienie zdarzenia. Jest to sposób, w Main jaki metoda nie zwraca się od razu, a aplikacja pozostaje uruchomiona do czasu Run lub WaitForShutdown powrotu.

Po wysłaniu sygnału do procesu inicjuje następującą sekwencję:

Hosting shutdown sequence diagram.

  1. Kontrolka przepływa od ConsoleLifetime do ApplicationLifetime , aby zgłosić ApplicationStopping zdarzenie. To sygnały WaitForShutdownAsync , aby odblokować Main kod wykonywania. W międzyczasie program obsługi sygnałów POSIX zwraca wartość z Cancel = true od czasu obsługi tego sygnału POSIX.
  2. Main Kod wykonywania rozpoczyna wykonywanie ponownie i nakazuje hostowi StopAsync()polecenie , który z kolei zatrzymuje wszystkie hostowane usługi i zgłasza wszystkie inne zatrzymane zdarzenia.
  3. WaitForShutdown Na koniec kończy działanie, co pozwala na wykonanie kodu przez dowolną aplikację, a Main metoda zostanie zakończona w sposób bezproblemowy.

Zobacz też