What is the Options pattern, and what is the difference between IOptions, IOptionsSnapshot and IOptionsMonitor?
Quick Answer
The Options pattern binds a configuration section to a strongly typed class and injects it. IOptions<T> — singleton, value read once, no reload. IOptionsSnapshot<T> — scoped, re-read per request, picks up file changes. IOptionsMonitor<T> — singleton with change notifications, works in singletons and background services.
The Options pattern is how I get strongly typed settings — I bind a config section like Smtp to an SmtpOptions class and inject it instead of pulling strings out of IConfiguration. The three interfaces differ in reload behaviour and lifetime. IOptions is a singleton, read once — fine for settings that don't change while the app runs, which is most of them. IOptionsSnapshot is scoped and re-reads per request, so it picks up changes to the config file, but you can't use it in a singleton. IOptionsMonitor is a singleton that supports change notifications, so it's what I use in a background service. I also add ValidateOnStart so bad config fails fast.
| IOptions<T> | IOptionsSnapshot<T> | IOptionsMonitor<T> | |
|---|---|---|---|
| Lifetime | Singleton | Scoped | Singleton |
| Reloads on config change | No | Yes (per request) | Yes (via OnChange / CurrentValue) |
| Usable in a singleton | Yes | No | Yes |
| Named options | No | Yes | Yes |
- Register:
services.Configure<SmtpOptions>(config.GetSection("Smtp")). - Add validation:
.ValidateDataAnnotations().ValidateOnStart()so a bad config fails at startup, not at first use. - Use
IOptionsfor settings that never change at run time (the common case),IOptionsSnapshotin request-scoped code that must see live edits,IOptionsMonitorin singletons / hosted services.