Pola opsi di .NET
Pola opsi menggunakan kelas untuk menyediakan akses yang sangat diketik ke grup pengaturan terkait. Saat pengaturan konfigurasi diisolasi oleh skenario ke dalam kelas terpisah, aplikasi mematuhi dua prinsip rekayasa perangkat lunak penting:
- Prinsip Pemisahan Antarmuka (ISP) atau Enkapulasi: Skenario (kelas) yang bergantung pada pengaturan konfigurasi hanya bergantung pada pengaturan konfigurasi yang mereka gunakan.
- Pemisahan Kekhawatiran: Pengaturan untuk berbagai bagian aplikasi tidak bergantung atau digabungkan satu sama lain.
Opsi juga menyediakan mekanisme untuk memvalidasi data konfigurasi. Untuk informasi selengkapnya, lihat bagian Validasi opsi.
Mengikat konfigurasi hierarkis
Cara yang lebih disukai untuk membaca nilai konfigurasi terkait adalah menggunakan pola opsi. Pola opsi dimungkinkan IOptions<TOptions> melalui antarmuka, di mana parameter TOptions
jenis generik dibatasi ke class
. Nantinya IOptions<TOptions>
dapat disediakan melalui injeksi dependensi. Untuk informasi selengkapnya, lihat Injeksi dependensi.
Misalnya, untuk membaca nilai konfigurasi yang disorot dari file appsettings.json :
{
"SecretKey": "Secret key value",
"TransientFaultHandlingOptions": {
"Enabled": true,
"AutoRetryDelay": "00:00:07"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Buat kelas TransientFaultHandlingOptions
berikut:
public sealed class TransientFaultHandlingOptions
{
public bool Enabled { get; set; }
public TimeSpan AutoRetryDelay { get; set; }
}
Saat menggunakan pola opsi, kelas opsi:
- Harus non-abstrak dengan konstruktor tanpa parameter publik
- Berisi properti baca-tulis publik untuk mengikat (bidang tidak terikat)
Kode berikut adalah bagian dari file C# Program.cs dan:
- Memanggil ConfigurationBinder.Bind untuk mengikat kelas
TransientFaultHandlingOptions
ke bagian"TransientFaultHandlingOptions"
. - Menampilkan data konfigurasi .
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using ConsoleJson.Example;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Configuration.Sources.Clear();
IHostEnvironment env = builder.Environment;
builder.Configuration
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true, true);
TransientFaultHandlingOptions options = new();
builder.Configuration.GetSection(nameof(TransientFaultHandlingOptions))
.Bind(options);
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={options.Enabled}");
Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={options.AutoRetryDelay}");
using IHost host = builder.Build();
// Application code should start here.
await host.RunAsync();
// <Output>
// Sample output:
Dalam kode sebelumnya, file konfigurasi JSON memiliki bagian yang "TransientFaultHandlingOptions"
terikat ke TransientFaultHandlingOptions
instans. Ini menghidrasi properti objek C# dengan nilai yang sesuai dari konfigurasi.
ConfigurationBinder.Get<T>
mengikat dan mengembalikan jenis yang ditentukan.
ConfigurationBinder.Get<T>
mungkin lebih nyaman daripada menggunakan ConfigurationBinder.Bind
. Contoh kode berikut menunjukkan cara menggunakan ConfigurationBinder.Get<T>
dengan kelas TransientFaultHandlingOptions
:
var options =
builder.Configuration.GetSection(nameof(TransientFaultHandlingOptions))
.Get<TransientFaultHandlingOptions>();
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={options.Enabled}");
Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={options.AutoRetryDelay}");
Dalam kode sebelumnya, ConfigurationBinder.Get<T>
digunakan untuk memperoleh instans TransientFaultHandlingOptions
objek dengan nilai propertinya yang diisi dari konfigurasi yang mendasarinya.
Penting
Kelas ConfigurationBinder mengekspos beberapa API, seperti .Bind(object instance)
dan .Get<T>()
yang tidak dibatasi ke class
. Saat menggunakan salah satu antarmuka Opsi, Anda harus mematuhi batasan kelas opsi yang disebutkan di atas.
Pendekatan alternatif saat menggunakan pola opsi adalah mengikat bagian "TransientFaultHandlingOptions"
dan menambahkannya ke kontainer layanan injeksi dependensi. Dalam kode berikut, TransientFaultHandlingOptions
ditambahkan ke kontainer layanan dengan Configure dan terikat ke konfigurasi:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.Configure<TransientFaultHandlingOptions>(
builder.Configuration.GetSection(
key: nameof(TransientFaultHandlingOptions)));
Dalam builder
contoh sebelumnya adalah instans .HostApplicationBuilder
Tip
Parameter key
adalah nama bagian konfigurasi untuk dicari. Ini tidak harus cocok dengan nama jenis yang mewakilinya. Misalnya, Anda dapat memiliki bagian bernama "FaultHandling"
dan dapat diwakili oleh TransientFaultHandlingOptions
kelas. Dalam hal ini, Anda akan meneruskan "FaultHandling"
ke fungsi sebagai gantinya GetSection . Operator nameof
digunakan sebagai kenyamanan ketika bagian bernama cocok dengan jenis yang sesuai dengannya.
Dengan menggunakan kode sebelumnya, kode berikut membaca opsi posisi:
using Microsoft.Extensions.Options;
namespace ConsoleJson.Example;
public sealed class ExampleService(IOptions<TransientFaultHandlingOptions> options)
{
private readonly TransientFaultHandlingOptions _options = options.Value;
public void DisplayValues()
{
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={_options.Enabled}");
Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={_options.AutoRetryDelay}");
}
}
Dalam kode sebelumnya, perubahan pada file konfigurasi JSON setelah aplikasi dimulai tidak dibaca. Untuk membaca perubahan setelah aplikasi dimulai, gunakan IOptionsSnapshot atau IOptionsMonitor untuk memantau perubahan saat terjadi, dan bereaksi sesuai.
Antarmuka opsi
- Tidak mendukung:
- Membaca data konfigurasi setelah aplikasi dimulai.
- Opsi bernama
- Terdaftar sebagai Singleton dan dapat disuntikkan ke dalam masa pakai layanan apa pun.
- Berguna dalam skenario di mana opsi harus dikomputasi ulang pada setiap resolusi injeksi, dalam masa pakai tercakup atau sementara. Untuk informasi selengkapnya, lihat Menggunakan IOptionsSnapshot untuk membaca data yang diperbarui.
- Terdaftar sebagai Cakupan dan oleh karena itu tidak dapat disuntikkan ke dalam layanan Singleton.
- Mendukung opsi yang diberi nama .
- Digunakan untuk mengambil opsi dan mengelola pemberitahuan opsi untuk
TOptions
instans. - Terdaftar sebagai Singleton dan dapat disuntikkan ke dalam masa pakai layanan apa pun.
- Mendukung:
- Mengubah pemberitahuan
- Opsi bernama
- Konfigurasi yang dapat dimuat ulang
- Invalidasi opsi selektif (IOptionsMonitorCache<TOptions>)
IOptionsFactory<TOptions> bertanggung jawab untuk membuat instans opsi baru. Ini memiliki satu Create metode. Implementasi default mengambil semua yang terdaftar IConfigureOptions<TOptions> dan IPostConfigureOptions<TOptions> dan menjalankan semua konfigurasi terlebih dahulu, diikuti oleh pasca-konfigurasi. Ini membedakan antara IConfigureNamedOptions<TOptions> dan IConfigureOptions<TOptions> dan hanya memanggil antarmuka yang sesuai.
IOptionsMonitorCache<TOptions> digunakan oleh IOptionsMonitor<TOptions> untuk menyimpan TOptions
instans.
IOptionsMonitorCache<TOptions> Instans opsi yang tidak valid di monitor sehingga nilai dikomputasi ulang (TryRemove). Nilai dapat diperkenalkan secara manual dengan TryAdd. Metode Clear ini digunakan ketika semua instans bernama harus dibuat ulang sesuai permintaan.
IOptionsChangeTokenSource<TOptions> digunakan untuk mengambil IChangeToken yang melacak perubahan pada instans yang mendasar TOptions
. Untuk informasi selengkapnya tentang primitif token perubahan, lihat Mengubah pemberitahuan.
Manfaat antarmuka opsi
Menggunakan jenis pembungkus generik memberi Anda kemampuan untuk memisahkan masa pakai opsi dari kontainer injeksi dependensi (DI). Antarmuka IOptions<TOptions>.Value menyediakan lapisan abstraksi, termasuk batasan generik, pada jenis opsi Anda. Ini memberikan manfaat berikut:
- Evaluasi
T
instans konfigurasi ditangguhkan untuk mengakses IOptions<TOptions>.Value, daripada ketika disuntikkan. Ini penting karena Anda dapat menggunakanT
opsi dari berbagai tempat dan memilih semantik seumur hidup tanpa mengubah apa pun tentangT
. - Saat mendaftarkan opsi jenis
T
, Anda tidak perlu mendaftarkanT
jenis secara eksplisit. Ini adalah kenyamanan ketika Anda menulis pustaka dengan default sederhana, dan Anda tidak ingin memaksa pemanggil untuk mendaftarkan opsi ke dalam kontainer DI dengan masa pakai tertentu. - Dari perspektif API, api memungkinkan batasan pada jenis
T
(dalam hal ini,T
dibatasi ke jenis referensi).
Menggunakan IOptionsSnapshot untuk membaca data yang diperbarui
Saat Anda menggunakan IOptionsSnapshot<TOptions>, opsi dihitung sekali per permintaan saat diakses dan di-cache selama masa pakai permintaan. Perubahan pada konfigurasi dibaca setelah aplikasi dimulai saat menggunakan penyedia konfigurasi yang mendukung pembacaan nilai konfigurasi yang diperbarui.
Perbedaan antara IOptionsMonitor
dan IOptionsSnapshot
adalah bahwa:
-
IOptionsMonitor
adalah layanan singleton yang mengambil nilai opsi saat ini kapan saja, yang sangat berguna dalam dependensi singleton. -
IOptionsSnapshot
adalah layanan terlingkup dan menyediakan rekam jepret opsi pada saatIOptionsSnapshot<T>
objek dibangun. Rekam jepret opsi dirancang untuk digunakan dengan dependensi sementara dan terlingkup.
Kode berikut menggunakan IOptionsSnapshot<TOptions>.
using Microsoft.Extensions.Options;
namespace ConsoleJson.Example;
public sealed class ScopedService(IOptionsSnapshot<TransientFaultHandlingOptions> options)
{
private readonly TransientFaultHandlingOptions _options = options.Value;
public void DisplayValues()
{
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={_options.Enabled}");
Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={_options.AutoRetryDelay}");
}
}
Kode berikut mendaftarkan instans konfigurasi yang TransientFaultHandlingOptions
mengikat terhadap:
builder.Services
.Configure<TransientFaultHandlingOptions>(
configurationRoot.GetSection(
nameof(TransientFaultHandlingOptions)));
Dalam kode sebelumnya, Configure<TOptions>
metode ini digunakan untuk mendaftarkan instans konfigurasi yang TOptions
akan mengikat, dan memperbarui opsi saat konfigurasi berubah.
IOptionsMonitor
Jenis ini IOptionsMonitor
mendukung pemberitahuan perubahan dan mengaktifkan skenario di mana aplikasi Anda mungkin perlu merespons perubahan sumber konfigurasi secara dinamis. Ini berguna ketika Anda perlu bereaksi terhadap perubahan data konfigurasi setelah aplikasi dimulai. Pemberitahuan perubahan hanya didukung untuk penyedia konfigurasi berbasis sistem file, seperti berikut ini:
- Microsoft.Extensions.Configuration.Ini
- Microsoft.Extensions.Configuration.Json
- Microsoft.Extensions.Configuration.KeyPerFile
- Microsoft.Extensions.Configuration.UserSecrets
- Microsoft.Extensions.Configuration.Xml
Untuk menggunakan pemantau opsi, objek opsi dikonfigurasi dengan cara yang sama dari bagian konfigurasi.
builder.Services
.Configure<TransientFaultHandlingOptions>(
configurationRoot.GetSection(
nameof(TransientFaultHandlingOptions)));
Contoh berikut menggunakan IOptionsMonitor<TOptions>:
using Microsoft.Extensions.Options;
namespace ConsoleJson.Example;
public sealed class MonitorService(IOptionsMonitor<TransientFaultHandlingOptions> monitor)
{
public void DisplayValues()
{
TransientFaultHandlingOptions options = monitor.CurrentValue;
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={options.Enabled}");
Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={options.AutoRetryDelay}");
}
}
Dalam kode sebelumnya, perubahan pada file konfigurasi JSON setelah aplikasi dimulai dibaca.
Tip
Beberapa sistem file, seperti kontainer Docker dan berbagi jaringan, mungkin tidak mengirim pemberitahuan perubahan dengan andal. Saat menggunakan IOptionsMonitor<TOptions> antarmuka di lingkungan ini, atur DOTNET_USE_POLLING_FILE_WATCHER
variabel lingkungan ke 1
atau true
untuk melakukan polling sistem file untuk perubahan. Interval di mana perubahan dijajaki adalah setiap empat detik dan tidak dapat dikonfigurasi.
Untuk informasi selengkapnya tentang kontainer Docker, lihat Membuat kontainer aplikasi .NET.
Dukungan opsi bernama menggunakan IConfigureNamedOptions
Opsi bernama:
- Berguna saat beberapa bagian konfigurasi mengikat properti yang sama.
- Peka huruf besar/kecil.
Pertimbangkan file appsettings.json berikut:
{
"Features": {
"Personalize": {
"Enabled": true,
"ApiKey": "aGEgaGEgeW91IHRob3VnaHQgdGhhdCB3YXMgcmVhbGx5IHNvbWV0aGluZw=="
},
"WeatherStation": {
"Enabled": true,
"ApiKey": "QXJlIHlvdSBhdHRlbXB0aW5nIHRvIGhhY2sgdXM/"
}
}
}
Daripada membuat dua kelas untuk mengikat Features:Personalize
dan Features:WeatherStation
, kelas berikut digunakan untuk setiap bagian:
public class Features
{
public const string Personalize = nameof(Personalize);
public const string WeatherStation = nameof(WeatherStation);
public bool Enabled { get; set; }
public string ApiKey { get; set; }
}
Kode berikut mengonfigurasi opsi bernama:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
// Omitted for brevity...
builder.Services.Configure<Features>(
Features.Personalize,
builder.Configuration.GetSection("Features:Personalize"));
builder.Services.Configure<Features>(
Features.WeatherStation,
builder.Configuration.GetSection("Features:WeatherStation"));
Kode berikut menampilkan opsi bernama:
public sealed class Service
{
private readonly Features _personalizeFeature;
private readonly Features _weatherStationFeature;
public Service(IOptionsSnapshot<Features> namedOptionsAccessor)
{
_personalizeFeature = namedOptionsAccessor.Get(Features.Personalize);
_weatherStationFeature = namedOptionsAccessor.Get(Features.WeatherStation);
}
}
Semua opsi diberi nama instans.
IConfigureOptions<TOptions> instans diperlakukan sebagai menargetkan Options.DefaultName
instans, yaitu string.Empty
.
IConfigureNamedOptions<TOptions> juga mengimplementasikan IConfigureOptions<TOptions>. Implementasi default dari IOptionsFactory<TOptions> memiliki logika untuk menggunakan masing-masing dengan tepat.
null
Opsi bernama digunakan untuk menargetkan semua instans bernama alih-alih instans bernama tertentu.
ConfigureAll dan PostConfigureAll gunakan konvensi ini.
OptionsBuilder API
OptionsBuilder<TOptions> digunakan untuk mengonfigurasi TOptions
instans.
OptionsBuilder
menyederhanakan pembuatan opsi bernama karena hanya satu parameter ke panggilan awal AddOptions<TOptions>(string optionsName)
alih-alih muncul di semua panggilan berikutnya. Validasi opsi dan ConfigureOptions
kelebihan beban yang menerima dependensi layanan hanya tersedia melalui OptionsBuilder
.
OptionsBuilder
digunakan di bagian Validasi opsi.
Menggunakan layanan DI untuk mengonfigurasi opsi
Saat mengonfigurasi opsi, Anda dapat menggunakan injeksi dependensi untuk mengakses layanan terdaftar, dan menggunakannya untuk mengonfigurasi opsi. Ini berguna ketika Anda perlu mengakses layanan untuk mengonfigurasi opsi. Layanan dapat diakses dari DI saat mengonfigurasi opsi dengan dua cara:
Teruskan delegasi konfigurasi untuk Mengonfigurasi pada OptionsBuilderTOptions>
OptionsBuilder<TOptions>
menyediakan kelebihan beban Konfigurasi yang memungkinkan penggunaan hingga lima layanan untuk mengonfigurasi opsi:builder.Services .AddOptions<MyOptions>("optionalName") .Configure<ExampleService, ScopedService, MonitorService>( (options, es, ss, ms) => options.Property = DoSomethingWith(es, ss, ms));
Buat jenis yang mengimplementasikan IConfigureOptions<TOptions> atau IConfigureNamedOptions<TOptions> dan mendaftarkan jenis sebagai layanan.
Disarankan untuk meneruskan delegasi konfigurasi ke Konfigurasi, karena membuat layanan lebih kompleks. Membuat jenis setara dengan apa yang dilakukan kerangka kerja saat memanggil Konfigurasikan. Memanggil Konfigurasi mendaftarkan generik IConfigureNamedOptions<TOptions>sementara , yang memiliki konstruktor yang menerima jenis layanan generik yang ditentukan.
Validasi opsi
Validasi opsi memungkinkan nilai opsi divalidasi.
Pertimbangkan file appsettings.json berikut:
{
"MyCustomSettingsSection": {
"SiteTitle": "Amazing docs from Awesome people!",
"Scale": 10,
"VerbosityLevel": 32
}
}
Kelas berikut mengikat ke bagian "MyCustomSettingsSection"
konfigurasi dan menerapkan beberapa DataAnnotations
aturan:
using System.ComponentModel.DataAnnotations;
namespace ConsoleJson.Example;
public sealed class SettingsOptions
{
public const string ConfigurationSectionName = "MyCustomSettingsSection";
[Required]
[RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
public required string SiteTitle { get; set; }
[Required]
[Range(0, 1_000,
ErrorMessage = "Value for {0} must be between {1} and {2}.")]
public required int Scale { get; set; }
[Required]
public required int VerbosityLevel { get; set; }
}
Di kelas sebelumnya SettingsOptions
, ConfigurationSectionName
properti berisi nama bagian konfigurasi yang akan diikat. Dalam skenario ini, objek opsi menyediakan nama bagian konfigurasinya.
Tip
Nama bagian konfigurasi tidak bergantung pada objek konfigurasi yang mengikatnya. Dengan kata lain, bagian konfigurasi bernama "FooBarOptions"
dapat terikat ke objek opsi bernama ZedOptions
. Meskipun mungkin umum untuk memberi nama yang sama, itu tidak perlu dan benar-benar dapat menyebabkan konflik nama.
Kode berikut:
-
AddOptions Panggilan untuk mendapatkan OptionsBuilder<TOptions> yang mengikat ke
SettingsOptions
kelas . -
ValidateDataAnnotations Panggilan untuk mengaktifkan validasi menggunakan
DataAnnotations
.
builder.Services
.AddOptions<SettingsOptions>()
.Bind(Configuration.GetSection(SettingsOptions.ConfigurationSectionName))
.ValidateDataAnnotations();
Metode ValidateDataAnnotations
ekstensi ditentukan dalam paket NuGet Microsoft.Extensions.Options.DataAnnotations .
Kode berikut menampilkan nilai konfigurasi atau melaporkan kesalahan validasi:
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace ConsoleJson.Example;
public sealed class ValidationService
{
private readonly ILogger<ValidationService> _logger;
private readonly IOptions<SettingsOptions> _config;
public ValidationService(
ILogger<ValidationService> logger,
IOptions<SettingsOptions> config)
{
_config = config;
_logger = logger;
try
{
SettingsOptions options = _config.Value;
}
catch (OptionsValidationException ex)
{
foreach (string failure in ex.Failures)
{
_logger.LogError("Validation error: {FailureMessage}", failure);
}
}
}
}
Kode berikut menerapkan aturan validasi yang lebih kompleks menggunakan delegasi:
builder.Services
.AddOptions<SettingsOptions>()
.Bind(Configuration.GetSection(SettingsOptions.ConfigurationSectionName))
.ValidateDataAnnotations()
.Validate(config =>
{
if (config.Scale != 0)
{
return config.VerbosityLevel > config.Scale;
}
return true;
}, "VerbosityLevel must be > than Scale.");
Validasi terjadi pada waktu proses, tetapi Anda dapat mengonfigurasinya agar terjadi saat startup dengan menautkan panggilan ke ValidateOnStart
:
builder.Services
.AddOptions<SettingsOptions>()
.Bind(Configuration.GetSection(SettingsOptions.ConfigurationSectionName))
.ValidateDataAnnotations()
.Validate(config =>
{
if (config.Scale != 0)
{
return config.VerbosityLevel > config.Scale;
}
return true;
}, "VerbosityLevel must be > than Scale.")
.ValidateOnStart();
Dimulai dengan .NET 8, Anda dapat menggunakan API alternatif, AddOptionsWithValidateOnStart<TOptions>(IServiceCollection, String), yang memungkinkan validasi pada awal untuk jenis opsi tertentu:
builder.Services
.AddOptionsWithValidateOnStart<SettingsOptions>()
.Bind(Configuration.GetSection(SettingsOptions.ConfigurationSectionName))
.ValidateDataAnnotations()
.Validate(config =>
{
if (config.Scale != 0)
{
return config.VerbosityLevel > config.Scale;
}
return true;
}, "VerbosityLevel must be > than Scale.");
IValidateOptions
untuk validasi kompleks
Kelas berikut mengimplementasikan IValidateOptions<TOptions>:
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
namespace ConsoleJson.Example;
sealed partial class ValidateSettingsOptions(
IConfiguration config)
: IValidateOptions<SettingsOptions>
{
public SettingsOptions? Settings { get; private set; } =
config.GetSection(SettingsOptions.ConfigurationSectionName)
.Get<SettingsOptions>();
public ValidateOptionsResult Validate(string? name, SettingsOptions options)
{
StringBuilder? failure = null;
if (!ValidationRegex().IsMatch(options.SiteTitle))
{
(failure ??= new()).AppendLine($"{options.SiteTitle} doesn't match RegEx");
}
if (options.Scale is < 0 or > 1_000)
{
(failure ??= new()).AppendLine($"{options.Scale} isn't within Range 0 - 1000");
}
if (Settings is { Scale: 0 } && Settings.VerbosityLevel <= Settings.Scale)
{
(failure ??= new()).AppendLine("VerbosityLevel must be > than Scale.");
}
return failure is not null
? ValidateOptionsResult.Fail(failure.ToString())
: ValidateOptionsResult.Success;
}
[GeneratedRegex("^[a-zA-Z''-'\\s]{1,40}$")]
private static partial Regex ValidationRegex();
}
IValidateOptions
memungkinkan pemindahan kode validasi ke dalam kelas.
Catatan
Contoh kode ini bergantung pada paket NuGet Microsoft.Extensions.Configuration.Json .
Menggunakan kode sebelumnya, validasi diaktifkan saat mengonfigurasi layanan dengan kode berikut:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
// Omitted for brevity...
builder.Services.Configure<SettingsOptions>(
builder.Configuration.GetSection(
SettingsOptions.ConfigurationSectionName));
builder.Services.TryAddEnumerable(
ServiceDescriptor.Singleton
<IValidateOptions<SettingsOptions>, ValidateSettingsOptions>());
Opsi pasca-konfigurasi
Atur pasca-konfigurasi dengan IPostConfigureOptions<TOptions>. Pasca-konfigurasi berjalan setelah semua IConfigureOptions<TOptions> konfigurasi terjadi, dan dapat berguna dalam skenario saat Anda perlu mengambil alih konfigurasi:
builder.Services.PostConfigure<CustomOptions>(customOptions =>
{
customOptions.Option1 = "post_configured_option1_value";
});
PostConfigure tersedia untuk pasca-konfigurasi opsi bernama:
builder.Services.PostConfigure<CustomOptions>("named_options_1", customOptions =>
{
customOptions.Option1 = "post_configured_option1_value";
});
Gunakan PostConfigureAll untuk mengonfigurasi semua instans konfigurasi pasca-konfigurasi:
builder.Services.PostConfigureAll<CustomOptions>(customOptions =>
{
customOptions.Option1 = "post_configured_option1_value";
});