loading experience

.NET

Configuration in .NET: the Options pattern and validation at startup

Typed settings validated before the application accepts requests: no more errors discovered in production.

Configuration in .NET: the Options pattern and validation at startup

Reading configuration with strings scattered around the code leads to typos discovered only in production. The Options pattern turns a configuration section into a typed, validated class.

With ValidateOnStart a wrong configuration stops startup, not production.
With ValidateOnStart a wrong configuration stops startup, not production.

The settings class

public class SmtpOptions
{
    [Required] public string Host { get; set; } = "";
    [Range(1, 65535)] public int Port { get; set; } = 587;
    [Required, EmailAddress] public string Sender { get; set; } = "";
}
{
  "Smtp": { "Host": "smtp.company.com", "Port": 587, "Sender": "noreply@company.com" }
}

Registration with validation at startup

builder.Services.AddOptions<SmtpOptions>()
    .BindConfiguration("Smtp")
    .ValidateDataAnnotations()
    .ValidateOnStart();

With ValidateOnStart the application does not start if the configuration is wrong: a clear error at deploy time beats an unsent email at three in the morning.

IOptions, IOptionsSnapshot or IOptionsMonitor?

  • IOptions<T>: values read once, ideal for settings that do not change.
  • IOptionsSnapshot<T>: recomputed on every request, useful if the configuration file can change at runtime.
  • IOptionsMonitor<T>: current value plus change notifications, suited to singletons.

Secrets

Passwords and keys do not belong in the configuration file saved in the repository: in development use user secrets, in production environment variables or a secrets store. The Options pattern does not change: it reads from all these sources in the same way.

Comments (0)

No comments yet.

Leave a comment