Silnie typowane opcje z IOptions
Powiąż sekcje konfiguracji z klasami POCO za pomocą IOptions , IOptionsSnapshot i IOptionsMonitor .
Silnie typowane opcje z IOptions to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.
Dlaczego warto używać silnie typowanych opcji?
Odczyt konfiguracji za pomocą IConfiguration["Key"] zwraca niejawnie typowane ciągi znaków. Wzorzec Options mapuje sekcje konfiguracji na klasy C#, zapewniając bezpieczeństwo na etapie kompilacji, funkcję IntelliSense i obsługę walidacji.
Definiowanie klasy opcji
Utwórz zwykłą klasę POCO, której nazwy właściwości odpowiadają kluczom JSON. Zgodnie z konwencją dodaj statyczną stałą SectionName, która identyfikuje sekcję konfiguracji.
// Configuration class
public class JwtOptions
{
public const string SectionName = "Jwt";
public string SecretKey { get; set; } = string.Empty;
public string Issuer { get; set; } = string.Empty;
public string Audience { get; set; } = string.Empty;
public int ExpiryMinutes { get; set; } = 60;
}
// appsettings.json:
{
"Jwt": {
"SecretKey": "my-very-secret-key",
"Issuer": "https://myapp.com",
"Audience": "https://myapp.com/api",
"ExpiryMinutes": 120
}
}Rejestrowanie opcji
Wywołaj Configure<T>, aby powiązać sekcję konfiguracji z klasą opcji. Spowoduje to zarejestrowanie IOptions<T>, IOptionsSnapshot<T> i IOptionsMonitor<T> w DI.
// Registration
builder.Services.Configure<JwtOptions>(
builder.Configuration.GetSection(JwtOptions.SectionName));
// Alternative shorthand:
builder.Services
.AddOptions<JwtOptions>()
.BindConfiguration(JwtOptions.SectionName);
// Consuming via IOptions<T>:
public class TokenService
{
private readonly JwtOptions _opts;
public TokenService(IOptions<JwtOptions> opts)
=> _opts = opts.Value;
public string CreateToken()
=> $"Issuer={_opts.Issuer}, Exp={_opts.ExpiryMinutes}m";
}IOptions a IOptionsSnapshot a IOptionsMonitor
Istnieją trzy warianty o różnym czasie życia i różnym zachowaniu podczas ponownego ładowania. Wybierz właściwy wariant do danego zastosowania.
// IOptions<T> — Singleton, reads config ONCE at startup
public class ApiClient(IOptions<ApiOptions> opts)
{
private readonly ApiOptions _opts = opts.Value; // never changes
}
// IOptionsSnapshot<T> — Scoped, reloads per request
public class ReportService(IOptionsSnapshot<ReportOptions> opts)
{
private readonly ReportOptions _opts = opts.Value; // fresh per request
}
// IOptionsMonitor<T> — Singleton, live updates + change notifications
public class FeatureService(IOptionsMonitor<FeatureFlags> monitor)
{
public bool IsEnabled(string feature)
=> monitor.CurrentValue.EnabledFeatures.Contains(feature);
}Walidacja opcji za pomocą atrybutów
Oznacz właściwości opcji atrybutami z System.ComponentModel.DataAnnotations i wywołaj ValidateDataAnnotations(), aby natychmiast wykrywać nieprawidłową konfigurację podczas uruchamiania.
using System.ComponentModel.DataAnnotations;
public class SmtpOptions
{
[Required]
public string Host { get; set; } = string.Empty;
[Range(1, 65535)]
public int Port { get; set; } = 587;
[Required, EmailAddress]
public string FromAddress { get; set; } = string.Empty;
}
// Register with validation:
builder.Services
.AddOptions<SmtpOptions>()
.BindConfiguration("Smtp")
.ValidateDataAnnotations()
.ValidateOnStart(); // fail at startup, not first useNiestandardowa walidacja za pomocą IValidateOptions
W przypadku złożonych reguł dotyczących wielu właściwości zaimplementuj IValidateOptions<T>, aby uzyskać pełną programową logikę walidacji.
public class JwtOptionsValidator : IValidateOptions<JwtOptions>
{
public ValidateOptionsResult Validate(string? name, JwtOptions opts)
{
var errors = new List<string>();
if (string.IsNullOrWhiteSpace(opts.SecretKey))
errors.Add("SecretKey must not be empty");
if (opts.SecretKey.Length < 32)
errors.Add("SecretKey must be at least 32 characters");
if (opts.ExpiryMinutes <= 0)
errors.Add("ExpiryMinutes must be positive");
return errors.Any()
? ValidateOptionsResult.Fail(errors)
: ValidateOptionsResult.Success;
}
}
builder.Services.AddSingleton<IValidateOptions<JwtOptions>, JwtOptionsValidator>();Post-Configure
PostConfigure jest wykonywane po wszystkich wywołaniach Configure i umożliwia nadpisywanie lub wyprowadzanie wartości — jest przydatne w przypadku właściwości obliczanych albo dostosowań zależnych od środowiska.
builder.Services.Configure<CacheOptions>(
builder.Configuration.GetSection("Cache"));
// Override in test environment:
builder.Services.PostConfigure<CacheOptions>(opts =>
{
if (builder.Environment.IsEnvironment("Testing"))
{
opts.AbsoluteExpirationMinutes = 1; // very short in tests
opts.UseDistributedCache = false; // use in-memory cache
}
});
// PostConfigure always runs LAST, even after AddOptions validatorsOpcje nazwane
Jeśli potrzebujesz wielu instancji tego samego typu opcji, na przykład dwóch serwerów SMTP, użyj opcji nazwanych, aby je rozróżnić.
// Register named options:
builder.Services.Configure<SmtpOptions>("Primary",
builder.Configuration.GetSection("Smtp:Primary"));
builder.Services.Configure<SmtpOptions>("Backup",
builder.Configuration.GetSection("Smtp:Backup"));
// Consume with IOptionsMonitor (supports named options):
public class EmailSender
{
private readonly SmtpOptions _primary;
private readonly SmtpOptions _backup;
public EmailSender(IOptionsMonitor<SmtpOptions> monitor)
{
_primary = monitor.Get("Primary");
_backup = monitor.Get("Backup");
}
}Skrócona forma BindConfiguration
Łańcuch AddOptions().BindConfiguration() to nowoczesny, płynny sposób na zarejestrowanie, powiązanie, zwalidowanie i natychmiastowe odrzucenie nieprawidłowej konfiguracji w jednym wyrażeniu.
// Full registration chain:
builder.Services
.AddOptions<DatabaseOptions>()
.BindConfiguration("Database") // bind section
.ValidateDataAnnotations() // attribute validation
.Validate(opts => // custom rule
opts.MaxPoolSize >= opts.MinPoolSize,
"MaxPoolSize must be >= MinPoolSize")
.ValidateOnStart(); // fail at startup
// Shorthand for simple cases:
builder.Services.AddOptions<AppOptions>()
.BindConfiguration(AppOptions.SectionName)
.ValidateOnStart();Praktyczny przykład: opcje flag funkcji
Kompletna konfiguracja opcji flag funkcji z obsługą ponownego ładowania, umożliwiająca zmianę przełączników w appsettings bez ponownego wdrażania aplikacji.
public class FeatureFlags
{
public bool EnableNewCheckout { get; set; }
public bool EnableAISearch { get; set; }
public bool EnableBetaDashboard { get; set; }
}
// appsettings.json:
// { "FeatureFlags": { "EnableNewCheckout": true, ... } }
builder.Services
.AddOptions<FeatureFlags>()
.BindConfiguration("FeatureFlags")
.ValidateOnStart();
// In a controller or service:
public class CheckoutController : ControllerBase
{
private readonly FeatureFlags _flags;
public CheckoutController(IOptionsMonitor<FeatureFlags> m)
=> _flags = m.CurrentValue;
[HttpGet("/checkout")]
public IActionResult Index() =>
_flags.EnableNewCheckout
? Ok("new checkout")
: Ok("legacy checkout");
}Szybkie sprawdzenie
Którego wariantu IOptions należy użyć w usłudze Singleton, która musi odzwierciedlać zmiany konfiguracji na żywo?
Podsumowanie: silnie typowane opcje z IOptions
Najważniejsze informacje:
- Wzorzec Options wiąże sekcje konfiguracji z obiektami POCO za pomocą
Configure<T>lubAddOptions<T>().BindConfiguration() IOptions<T>: Singleton, odczytuje wartości raz podczas uruchamianiaIOptionsSnapshot<T>: Scoped, ponownie ładuje wartości dla każdego żądania — nie wstrzykuj go do SingletonówIOptionsMonitor<T>: bezpieczny dla Singletonów, zapewnia bieżącą wartość przezCurrentValuei powiadomienia przezOnChange- Waliduj za pomocą DataAnnotations +
ValidateDataAnnotations()+ValidateOnStart() - Opcje nazwane służą do obsługi wielu instancji tego samego typu
Ucz się C# dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 93
- Lekcje
- 346
Często zadawane pytania
Czy lekcja „Silnie typowane opcje z IOptions” jest bezpłatna?
Tak — pełny tekst „Silnie typowane opcje z IOptions” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Silnie typowane opcje z IOptions”?
Powiąż sekcje konfiguracji z klasami POCO za pomocą IOptions , IOptionsSnapshot i IOptionsMonitor . Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć C# Academy?
Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Silnie typowane opcje z IOptions”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?
Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Źródła i dostawcy konfiguracji
- Silnie typowane opcje z IOptions
- Walidacja opcji i opcje nazwane
- Zarządzanie sekretami