๐ฏ Key Takeaways: Clean, type-safe configuration binding with validation, reloading, and dependency injection. The definitive guide to IOptions, IOptionsSnapshot, and IOptionsMonitor.
Using strings and magic values in your code? The Options Pattern brings type-safety and flexibility to your configuration.
๐ฆ Basic Setup
// appsettings.json
{
"EmailSettings": {
"SmtpServer": "smtp.gmail.com",
"SmtpPort": 587,
"SenderEmail": "noreply@myapp.com",
"SenderName": "MyApp",
"EnableSsl": true,
"MaxRetries": 3
}
}
// Model
public class EmailSettings
{
public string SmtpServer { get; set; } = string.Empty;
public int SmtpPort { get; set; }
public string SenderEmail { get; set; } = string.Empty;
public string SenderName { get; set; } = string.Empty;
public bool EnableSsl { get; set; }
public int MaxRetries { get; set; }
}
// Registration
builder.Services.Configure<EmailSettings>(
builder.Configuration.GetSection("EmailSettings"));
๐ Three Options Types
// 1. IOptions<T> - Singleton (static after startup)
public class EmailService
{
private readonly EmailSettings _settings;
public EmailService(IOptions<EmailSettings> options)
{
_settings = options.Value; // โ
Single snapshot
}
}
// 2. IOptionsSnapshot<T> - Scoped (reloads on change)
public class EmailService
{
private readonly IOptionsSnapshot<EmailSettings> _options;
public EmailService(IOptionsSnapshot<EmailSettings> options)
{
_options = options; // โ
Fresh each time
}
public void SendEmail()
{
var settings = _options.Value; // โ
Reloaded per request
}
}
// 3. IOptionsMonitor<T> - Singleton (auto-reloads, change notifications)
public class EmailService
{
private readonly IOptionsMonitor<EmailSettings> _monitor;
private readonly IDisposable? _changeListener;
public EmailService(IOptionsMonitor<EmailSettings> monitor)
{
_monitor = monitor;
_changeListener = _monitor.OnChange(settings =>
{
Console.WriteLine("Email config changed!");
// React to changes
});
}
}
โ Validation
// With validation
public class EmailSettings
{
[Required]
[MinLength(5)]
public string SmtpServer { get; set; } = string.Empty;
[Range(1, 65535)]
public int SmtpPort { get; set; }
[EmailAddress]
public string SenderEmail { get; set; } = string.Empty;
[Required]
public string SenderName { get; set; } = string.Empty;
[Range(1, 10)]
public int MaxRetries { get; set; }
}
// Validate on startup
builder.Services.AddOptions<EmailSettings>()
.Bind(builder.Configuration.GetSection("EmailSettings"))
.ValidateDataAnnotations()
.Validate(settings => settings.SmtpPort != 25, "SmtpPort cannot be 25(unsecure)")
.ValidateOnStart();
// ๐ฅ Throws exception if config is invalid!
๐ก Pro Tip: Environment – Specific Config
// appsettings.Development.json
{
"EmailSettings": {
"SmtpServer": "localhost",
"SmtpPort": 1025,
"MaxRetries": 1
}
}
// appsettings.Production.json
{
"EmailSettings": {
"SmtpServer": "smtp.sendgrid.net",
"SmtpPort": 587,
"MaxRetries": 5
}
}
// ๐ก Automatic based on ASPNETCORE_ENVIRONMENT
