Opzioni fortemente tipizzate con IOptions
Colleghi le sezioni di configurazione a classi POCO usando IOptions , IOptionsSnapshot e IOptionsMonitor .
Opzioni fortemente tipizzate con IOptions è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 4 lezioni in totale.
Perché utilizzare opzioni fortemente tipizzate?
La lettura della configurazione con IConfiguration["Key"] restituisce stringhe prive di tipo. Il pattern delle opzioni associa le sezioni di configurazione a classi C#, offrendo sicurezza in fase di compilazione, IntelliSense e supporto per la convalida.
Definizione di una classe Options
Crei una semplice classe POCO i cui nomi delle proprietà corrispondano alle chiavi JSON. Per convenzione, aggiunga una costante statica SectionName per identificare la sezione di configurazione.
// 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
}
}Registrazione delle opzioni
Chiami Configure<T> per associare una sezione di configurazione alla classe delle opzioni. In questo modo registra IOptions<T>, IOptionsSnapshot<T> e IOptionsMonitor<T> nella 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, IOptionsSnapshot e IOptionsMonitor a confronto
Esistono tre varianti, con durate e comportamenti di ricaricamento diversi. Scelga quella più adatta al proprio caso d'uso.
// 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);
}Convalida delle opzioni con gli attributi
Decori le proprietà delle opzioni con gli attributi di System.ComponentModel.DataAnnotations e chiami ValidateDataAnnotations() per interrompere subito l'avvio se la configurazione non è valida.
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 useConvalida personalizzata con IValidateOptions
Per regole complesse tra più proprietà, implementi IValidateOptions<T> per ottenere una logica di convalida programmatica completa.
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-configurazione
PostConfigure viene eseguito dopo tutte le chiamate a Configure e consente di sovrascrivere o derivare valori, risultando utile per proprietà calcolate o adattamenti specifici dell'ambiente.
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 validatorsOpzioni denominate
Quando sono necessarie più istanze dello stesso tipo di opzioni, ad esempio due server SMTP, utilizzi le opzioni denominate per distinguerle.
// 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");
}
}Forma abbreviata di BindConfiguration
La catena AddOptions().BindConfiguration() è il moderno approccio fluente per registrare, associare, convalidare e interrompere subito l'esecuzione, tutto in un'unica espressione.
// 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();Caso reale: opzioni per i flag delle funzionalità
Una configurazione completa delle opzioni per i flag delle funzionalità, con supporto per il ricaricamento, che consente di modificare gli interruttori in appsettings senza ridistribuire l'applicazione.
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");
}Verifica rapida
Quale variante di IOptions dovrebbe utilizzare in un servizio Singleton che deve riflettere le modifiche alla configurazione in tempo reale?
Riepilogo: opzioni fortemente tipizzate con IOptions
Concetti chiave:
- Il pattern delle opzioni associa le sezioni di configurazione a oggetti POCO tramite
Configure<T>oAddOptions<T>().BindConfiguration() IOptions<T>: Singleton, legge i valori una volta all'avvioIOptionsSnapshot<T>: Scoped, ricarica i valori a ogni richiesta — non lo inietti nei SingletonIOptionsMonitor<T>: sicuro nei Singleton, conCurrentValueaggiornato in tempo reale eOnChange- Convalidi con DataAnnotations +
ValidateDataAnnotations()+ValidateOnStart() - Utilizzi le opzioni denominate per più istanze dello stesso tipo
Domande Frequenti
La lezione «Opzioni fortemente tipizzate con IOptions» è gratuita?
Sì — il testo completo di «Opzioni fortemente tipizzate con IOptions» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 4 lezioni in totale.
Cosa imparerò in «Opzioni fortemente tipizzate con IOptions»?
Colleghi le sezioni di configurazione a classi POCO usando IOptions , IOptionsSnapshot e IOptionsMonitor . Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare C# Academy?
Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «Opzioni fortemente tipizzate con IOptions»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione C# Academy?
Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Fonti e provider di configurazione
- Opzioni fortemente tipizzate con IOptions
- Convalida delle opzioni e opzioni denominate
- Gestione dei segreti