Host Umum .NET
Dalam artikel ini, Anda mempelajari tentang berbagai pola untuk mengonfigurasi dan membangun Host Generik .NET yang tersedia dalam paket NuGet Microsoft.Extensions.Hosting . Host Generik .NET bertanggung jawab atas startup aplikasi dan manajemen seumur hidup. Template Layanan Pekerja membuat Host Umum .NET, HostApplicationBuilder. Host Umum dapat digunakan dengan jenis aplikasi .NET lain, seperti aplikasi Konsol.
Host adalah objek yang mencakup sumber daya dan fungsionalitas masa pakai aplikasi, seperti:
- Injeksi dependensi (DI)
- Pencatatan
- Konfigurasi
- Penonaktifan aplikasi
- Implementasi
IHostedService
Saat dimulai, host memanggil IHostedService.StartAsync pada setiap implementasi IHostedService yang terdaftar dalam kumpulan layanan yang dihosting kontainer layanan. Dalam aplikasi layanan pekerja, semua implementasi IHostedService
yang berisi instans BackgroundService mendapati metode BackgroundService.ExecuteAsync-nya dipanggil.
Alasan utama untuk menyertakan semua sumber daya aplikasi yang saling bergantung dalam satu objek adalah pengelolaan masa pakai: kontrol atas pengaktifan dan penonaktifan aplikasi dengan baik.
Menyiapkan host
Host biasanya dikonfigurasi, dibangun, dan dijalankan oleh kode di kelas Program
. Metode Main
:
- Memanggil metode CreateApplicationBuilder untuk membuat dan mengonfigurasi objek penyusun.
- Panggil Build() untuk membuat instans IHost.
- Panggil Run atau metode RunAsync pada objek host.
Template Layanan Pekerja .NET menghasilkan kode berikut untuk membuat Host Umum:
using Example.WorkerService;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<Worker>();
IHost host = builder.Build();
host.Run();
Untuk informasi selengkapnya tentang Layanan Pekerja, lihat Layanan Pekerja di .NET.
Pengaturan penyusun host
Metode CreateApplicationBuilder:
- Mengatur akar konten ke jalur yang ditampilkan oleh GetCurrentDirectory().
-
Memuat konfigurasi host dari:
- Variabel lingkungan yang diawali dengan
DOTNET_
. - Argumen baris perintah.
- Variabel lingkungan yang diawali dengan
- Memuat konfigurasi aplikasi dari:
- appsettings.json.
- appsettings.{Environment}.json.
- Pengelola Rahasia saat aplikasi berjalan di lingkungan
Development
. - Variabel lingkungan.
- Argumen baris perintah.
- Menambahkan penyedia pengelogan berikut:
- Konsol
- Debug
- EventSource
- EventLog (hanya saat menjalankan di Windows)
- Mengaktifkan validasi cakupan dan validasi dependensi saat lingkungan
Development
.
HostApplicationBuilder.Services adalah Microsoft.Extensions.DependencyInjection.IServiceCollection instans. Layanan ini digunakan untuk membangun yang IServiceProvider digunakan dengan injeksi dependensi untuk menyelesaikan layanan terdaftar.
Layanan yang disediakan kerangka kerja
Saat Anda memanggil IHostBuilder.Build() atau HostApplicationBuilder.Build(), layanan berikut didaftarkan secara otomatis:
Pembangun host berbasis skenario tambahan
Jika Anda membangun untuk web atau menulis aplikasi terdistribusi, Anda mungkin perlu menggunakan pembuat host yang berbeda. Pertimbangkan daftar penyusun host tambahan berikut:
- DistributedApplicationBuilder: Penyusun untuk membuat aplikasi terdistribusi. Untuk informasi selengkapnya, lihat .NET Aspire.
- WebApplicationBuilder: Penyusun untuk aplikasi dan layanan web. Untuk informasi selengkapnya, lihat ASP.NET Core.
-
WebHostBuilder: Penyusun untuk
IWebHost
. Untuk informasi selengkapnya, lihat host web ASP.NET Core.
IHostApplicationLifetime
Injeksikan layanan IHostApplicationLifetime ke kelas mana pun untuk menangani tugas pasca-pengaktifan dan penonaktifan dengan baik. Tiga properti pada antarmuka adalah token pembatalan yang digunakan untuk mendaftarkan metode penanganan aktivitas mulai aplikasi dan penghentian aplikasi. Antarmuka juga mencakup metode StopApplication().
Contoh berikut adalah implementasi IHostedService dan IHostedLifecycleService yang mendaftarkan IHostApplicationLifetime
peristiwa:
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace AppLifetime.Example;
public sealed class ExampleHostedService : IHostedService, IHostedLifecycleService
{
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);
}
Task IHostedLifecycleService.StartingAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("1. StartingAsync has been called.");
return Task.CompletedTask;
}
Task IHostedService.StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("2. StartAsync has been called.");
return Task.CompletedTask;
}
Task IHostedLifecycleService.StartedAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("3. StartedAsync has been called.");
return Task.CompletedTask;
}
private void OnStarted()
{
_logger.LogInformation("4. OnStarted has been called.");
}
private void OnStopping()
{
_logger.LogInformation("5. OnStopping has been called.");
}
Task IHostedLifecycleService.StoppingAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("6. StoppingAsync has been called.");
return Task.CompletedTask;
}
Task IHostedService.StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("7. StopAsync has been called.");
return Task.CompletedTask;
}
Task IHostedLifecycleService.StoppedAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("8. StoppedAsync has been called.");
return Task.CompletedTask;
}
private void OnStopped()
{
_logger.LogInformation("9. OnStopped has been called.");
}
}
Template Layanan Pekerja dapat dimodifikasi untuk menambahkan implementasi ExampleHostedService
:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using AppLifetime.Example;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<ExampleHostedService>();
using IHost host = builder.Build();
await host.RunAsync();
Aplikasi akan menulis output sampel berikut:
// Sample output:
// info: AppLifetime.Example.ExampleHostedService[0]
// 1.StartingAsync has been called.
// info: AppLifetime.Example.ExampleHostedService[0]
// 2.StartAsync has been called.
// info: AppLifetime.Example.ExampleHostedService[0]
// 3.StartedAsync has been called.
// info: AppLifetime.Example.ExampleHostedService[0]
// 4.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\net8.0
// info: AppLifetime.Example.ExampleHostedService[0]
// 5.OnStopping has been called.
// info: Microsoft.Hosting.Lifetime[0]
// Application is shutting down...
// info: AppLifetime.Example.ExampleHostedService[0]
// 6.StoppingAsync has been called.
// info: AppLifetime.Example.ExampleHostedService[0]
// 7.StopAsync has been called.
// info: AppLifetime.Example.ExampleHostedService[0]
// 8.StoppedAsync has been called.
// info: AppLifetime.Example.ExampleHostedService[0]
// 9.OnStopped has been called.
Output menunjukkan urutan semua dari berbagai peristiwa siklus hidup:
IHostedLifecycleService.StartingAsync
IHostedService.StartAsync
IHostedLifecycleService.StartedAsync
IHostApplicationLifetime.ApplicationStarted
Ketika aplikasi dihentikan, misalnya dengan Ctrl+C, peristiwa berikut dinaikkan:
IHostApplicationLifetime.ApplicationStopping
IHostedLifecycleService.StoppingAsync
IHostedService.StopAsync
IHostedLifecycleService.StoppedAsync
IHostApplicationLifetime.ApplicationStopped
IHostLifetime
Implementasi IHostLifetime mengontrol waktu host dimulai dan dihentikan. Implementasi terakhir yang terdaftar akan digunakan.
Microsoft.Extensions.Hosting.Internal.ConsoleLifetime
adalah implementasi IHostLifetime
default. Untuk informasi selengkapnya tentang mekanisme masa pakai penonaktifan, lihat Penonaktifan host.
Antarmuka IHostLifetime
mengekspos IHostLifetime.WaitForStartAsync metode, yang disebut pada awalnya IHost.StartAsync
akan menunggu sampai selesai sebelum melanjutkan. Ini dapat digunakan untuk menunda startup hingga disinyalir oleh peristiwa eksternal.
Selain itu, IHostLifetime
antarmuka mengekspos IHostLifetime.StopAsync metode, yang dipanggil dari IHost.StopAsync
untuk menunjukkan bahwa host berhenti dan saatnya untuk mematikan.
IHostEnvironment
Injeksikan layanan IHostEnvironment ke dalam kelas untuk mendapatkan informasi tentang pengaturan berikut:
- IHostEnvironment.ApplicationName
- IHostEnvironment.ContentRootFileProvider
- IHostEnvironment.ContentRootPath
- IHostEnvironment.EnvironmentName
Selain itu, layanan ini IHostEnvironment
memaparkan kemampuan untuk mengevaluasi lingkungan dengan bantuan metode ekstensi ini:
- HostingEnvironmentExtensions.IsDevelopment
- HostingEnvironmentExtensions.IsEnvironment
- HostingEnvironmentExtensions.IsProduction
- HostingEnvironmentExtensions.IsStaging
Konfigurasi host
Konfigurasi host digunakan untuk mengonfigurasi properti implementasi IHostEnvironment.
Konfigurasi host tersedia di HostApplicationBuilderSettings.Configuration properti dan implementasi lingkungan tersedia di IHostApplicationBuilder.Environment properti. Untuk mengonfigurasi host, akses Configuration
properti dan panggil salah satu metode ekstensi yang tersedia.
Untuk menambahkan konfigurasi host, pertimbangkan contoh berikut:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
HostApplicationBuilderSettings settings = new()
{
Args = args,
Configuration = new ConfigurationManager(),
ContentRootPath = Directory.GetCurrentDirectory(),
};
settings.Configuration.AddJsonFile("hostsettings.json", optional: true);
settings.Configuration.AddEnvironmentVariables(prefix: "PREFIX_");
settings.Configuration.AddCommandLine(args);
HostApplicationBuilder builder = Host.CreateApplicationBuilder(settings);
using IHost host = builder.Build();
// Application code should start here.
await host.RunAsync();
Kode sebelumnya:
- Mengatur akar konten ke jalur yang ditampilkan oleh GetCurrentDirectory().
- Memuat konfigurasi host dari:
- hostsettings.json.
- Variabel lingkungan yang diawali dengan
PREFIX_
. - Argumen baris perintah.
Konfigurasi aplikasi
Konfigurasi aplikasi dibuat dengan memanggil ConfigureAppConfiguration pada IHostApplicationBuilder. Properti IHostApplicationBuilder.Configuration publik memungkinkan konsumen untuk membaca dari atau membuat perubahan pada konfigurasi yang ada menggunakan metode ekstensi yang tersedia.
Untuk informasi selengkapnya, lihat Konfigurasi di .NET.
Penonaktifan host
Ada beberapa cara di mana proses yang dihosting dihentikan. Paling umum, proses yang dihosting dapat dihentikan dengan cara berikut:
- Jika seseorang tidak memanggil Run atau HostingAbstractionsHostExtensions.WaitForShutdown dan aplikasi keluar secara normal setelah
Main
selesai. - Jika aplikasi crash.
- Jika aplikasi dimatikan secara paksa menggunakan SIGKILL (atau Ctrl+Z).
Kode hosting tidak bertanggung jawab untuk menangani skenario ini. Pemilik proses perlu menanganinya sama dengan aplikasi lain. Ada beberapa cara lain di mana proses layanan yang dihosting dapat dihentikan:
- Jika
ConsoleLifetime
digunakan (UseConsoleLifetime), ia mendengarkan sinyal berikut dan mencoba menghentikan host dengan anggun. - Jika aplikasi memanggil Environment.Exit.
Logika hosting bawaan menangani skenario ini, khususnya ConsoleLifetime
kelas .
ConsoleLifetime
mencoba menangani sinyal "matikan" SIGINT, SIGQUIT, dan SIGTERM untuk memungkinkan keluar dengan baik ke aplikasi.
Sebelum .NET 6, tidak ada cara bagi kode .NET untuk menangani SIGTERM dengan baik. Untuk mengatasi batasan ini, ConsoleLifetime
akan berlangganan ke System.AppDomain.ProcessExit. Saat ProcessExit
dimunculkan, ConsoleLifetime
akan memberi sinyal ke host untuk berhenti dan memblokir alur ProcessExit
, yang menunggu host berhenti.
Handler keluar proses akan memungkinkan kode pembersihan dalam aplikasi berjalan—misalnya, IHost.StopAsync dan kode setelah HostingAbstractionsHostExtensions.Run dalam Main
metode .
Namun, ada masalah lain dengan pendekatan ini karena SIGTERM bukan satu-satunya cara ProcessExit
yang diangkat. SIGTERM juga dinaikkan saat kode aplikasi memanggil Environment.Exit
.
Environment.Exit
bukanlah cara yang baik untuk mematikan proses dalam model aplikasi Microsoft.Extensions.Hosting
. Hal ini memunculkan peristiwa ProcessExit
dan kemudian keluar dari proses. Akhir metode Main
tidak dijalankan. Utas latar belakang dan latar depan dihentikan, dan finally
blok tidak dijalankan.
Karena ConsoleLifetime
memblokir ProcessExit
saat menunggu host dimatikan, perilaku ini menyebabkan kebuntuan dari Environment.Exit
yang juga memblokir menunggu panggilan ke ProcessExit
. Selain itu, karena penanganan SIGTERM mencoba mematikan proses dengan baik, ConsoleLifetime
akan mengatur ExitCode ke 0
, yang mengacaukan kode keluar pengguna yang diteruskan ke Environment.Exit
.
Di .NET 6, sinyal POSIX didukung dan ditangani. Menangani ConsoleLifetime
SIGTERM dengan anggun, dan tidak lagi terlibat ketika Environment.Exit
dipanggil.
Tip
Untuk .NET 6+, ConsoleLifetime
tidak lagi memiliki logika untuk menangani skenario Environment.Exit
. Aplikasi yang memanggil Environment.Exit
dan perlu menjalankan logika pembersihan dapat berlangganan ke ProcessExit
dengan sendirinya. Hosting tidak akan lagi mencoba menghentikan host dengan anggun dalam skenario ini.
Jika aplikasi Anda menggunakan hosting, dan Anda ingin menghentikan host dengan baik, Anda dapat memanggil IHostApplicationLifetime.StopApplication dan bukan Environment.Exit
.
Proses penonaktifan hosting
Diagram urutan berikut menunjukkan cara sinyal ditangani secara internal dalam kode hosting. Sebagian besar pengguna tidak perlu memahami proses ini. Tetapi bagi pengembang yang membutuhkan pemahaman mendalam, visual yang baik dapat membantu Anda memulai.
Setelah host dimulai, saat pengguna memanggil Run
atau WaitForShutdown
, penanganan akan terdaftar untuk IApplicationLifetime.ApplicationStopping. Eksekusi dijeda di WaitForShutdown
, yang menunggu peristiwa ApplicationStopping
dimunculkan. Metode Main
ini tidak segera kembali, dan aplikasi tetap berjalan sampai Run
atau WaitForShutdown
kembali.
Saat dikirim ke proses, sinyal akan memulai urutan berikut:
- Kontrol mengalir dari
ConsoleLifetime
keApplicationLifetime
untuk memunculkan peristiwaApplicationStopping
. Hal ini memberi sinyalWaitForShutdownAsync
untuk membuka blokir kode eksekusiMain
. Sementara itu, handler sinyal POSIX kembali denganCancel = true
karena sinyal POSIX telah ditangani. - Kode eksekusi
Main
mulai dijalankan lagi dan memberi tahu host keStopAsync()
, yang pada gilirannya menghentikan semua layanan yang dihosting, dan memunculkan peristiwa lain yang dihentikan. - Akhirnya,
WaitForShutdown
keluar, memungkinkan kode pembersihan aplikasi apa pun dijalankan, dan agarMain
metode keluar dengan anggun.
Penonaktifan host dalam skenario server web
Ada berbagai skenario umum lainnya di mana penonaktifan anggun berfungsi di Kestrel untuk protokol HTTP/1.1 dan HTTP/2, dan bagaimana Anda dapat mengonfigurasinya di lingkungan yang berbeda dengan load balancer untuk menguras lalu lintas dengan lancar. Meskipun konfigurasi server web berada di luar cakupan artikel ini, Anda dapat menemukan informasi selengkapnya tentang Mengonfigurasi opsi untuk dokumentasi server web ASP.NET Core Kestrel.
Ketika Host menerima sinyal matikan (misalnya, Ctrl+C atau StopAsync
), Host akan memberi tahu aplikasi dengan memberi sinyal ApplicationStopping. Anda harus berlangganan acara ini jika Anda memiliki operasi jangka panjang yang perlu diselesaikan dengan baik.
Selanjutnya, Host memanggil IServer.StopAsync dengan batas waktu mati yang dapat Anda konfigurasi (default 30s). Kestrel (dan Http.Sys) menutup pengikatan port mereka dan berhenti menerima koneksi baru. Mereka juga memberi tahu koneksi saat ini untuk berhenti memproses permintaan baru. Untuk HTTP/2 dan HTTP/3, pesan awal GOAWAY
dikirim ke klien. Untuk HTTP/1.1, mereka menghentikan perulangan koneksi karena permintaan diproses secara berurutan. IIS berperilaku berbeda, dengan menolak permintaan baru dengan kode status 503.
Permintaan aktif memiliki waktu hingga batas waktu mati selesai. Jika semuanya selesai sebelum waktu habis, server mengembalikan kontrol ke host lebih cepat. Jika waktu habis berakhir, koneksi dan permintaan yang tertunda dibatalkan secara paksa, yang dapat menyebabkan kesalahan dalam log dan ke klien.
Pertimbangan load balancer
Untuk memastikan transisi klien yang lancar ke tujuan baru saat bekerja dengan load balancer, Anda dapat mengikuti langkah-langkah berikut:
- Munculkan instans baru dan mulai seimbangkan lalu lintas ke instans tersebut (Anda mungkin sudah memiliki beberapa instans untuk tujuan penskalaan).
- Nonaktifkan atau hapus instans lama dalam konfigurasi load balancer sehingga berhenti menerima lalu lintas baru.
- Beri sinyal instans lama untuk dimatikan.
- Tunggu hingga habis atau waktu habis.
Lihat juga
- Injeksi dependensi di .NET
- Pengelogan dalam .NET
- Konfigurasi di .NET
- Layanan Pekerja .NET
- ASP.NET Core Web Host
- konfigurasi server web ASP.NET Core Kestrel
- Bug host generik harus dibuat di repositori github.com/dotnet/runtime