Repository navigation
Options Feature Compatibility
davidkallesen edited this page Mar 12, 2026
·
1 revision
This page documents which [OptionsBinding] features can be combined and which combinations are invalid.
| Feature | Singleton (IOptions<T>) |
Scoped (IOptionsSnapshot<T>) |
Monitor (IOptionsMonitor<T>) |
|---|---|---|---|
ValidateDataAnnotations |
✅ | ✅ | ✅ |
ValidateOnStart |
✅ | ✅ | ✅ |
ErrorOnMissingKeys |
✅ | ✅ | ✅ |
Validator (custom) |
✅ | ✅ | ✅ |
PostConfigure |
✅ | ✅ | ✅ |
OnChange |
❌ ATCOPT004 | ❌ ATCOPT004 | ✅ |
Name (named options) |
✅ | ✅ | ✅ |
ChildSections |
✅ | ✅ | ✅ |
ConfigureAll |
✅ | ✅ | ✅ |
AlsoRegisterDirectType |
✅ | ✅ | ✅ |
OnChange generates a hosted service (IHostedService) that subscribes to IOptionsMonitor<T>.OnChange(). This API is only available on IOptionsMonitor<T>, so OptionsLifetime.Monitor is required.
| Feature | Single Instance | Named Options |
|---|---|---|
ValidateDataAnnotations |
✅ | ✅ |
ValidateOnStart |
✅ | ✅ |
ErrorOnMissingKeys |
✅ | ✅ |
Validator (custom) |
✅ | ✅ |
PostConfigure |
✅ | ❌ ATCOPT008 |
OnChange |
✅ | ❌ ATCOPT005 |
ConfigureAll |
❌ ATCOPT011 | ✅ (requires 2+) |
AlsoRegisterDirectType |
✅ | ✅ |
-
OnChange+ named options: Not supported becauseOnChangegenerates a single hosted service — it can't distinguish between named instances. -
PostConfigure+ named options: Not supported becausePostConfigureapplies to a single instance. UseConfigureAllto set defaults across all named instances. -
ConfigureAllrequires 2+ named options: It only makes sense when you have multiple named instances to apply defaults to.
| Rule | Diagnostic |
|---|---|
Cannot combine ChildSections with Name
|
ATCOPT014 |
ChildSections requires at least 2 items |
ATCOPT015 |
| Array items cannot be null or empty | ATCOPT016 |
ChildSections is syntactic sugar that generates multiple [OptionsBinding] attributes with Name set automatically. Therefore you cannot also set Name manually.
Do you need live-reload of configuration values?
├── YES → Do you need change notifications?
│ ├── YES → Use Monitor + OnChange
│ └── NO → Use Monitor (reads latest value on every access)
└── NO → Do you need per-request isolation?
├── YES → Use Scoped (IOptionsSnapshot<T>)
└── NO → Use Singleton (IOptions<T>) — DEFAULT
| Lifetime | Interface | Behavior | Best For |
|---|---|---|---|
| Singleton (default) | IOptions<T> |
Reads config once at startup | Static configuration, connection strings |
| Scoped | IOptionsSnapshot<T> |
Reads latest per request/scope | Per-request settings, multi-tenant config |
| Monitor | IOptionsMonitor<T> |
Always reads latest, supports OnChange
|
Feature flags, runtime toggles |
Do you have DataAnnotation attributes on properties?
├── YES → Set ValidateDataAnnotations = true
│ └── Do you want fail-fast at startup?
│ ├── YES → Also set ValidateOnStart = true
│ └── NO → Validation runs on first access
└── NO → Do you need custom validation logic?
├── YES → Create IValidateOptions<T> + set Validator = typeof(...)
│ └── Also set ValidateOnStart = true for fail-fast
└── NO → Is the section required to exist?
├── YES → Set ErrorOnMissingKeys = true, ValidateOnStart = true
└── NO → No validation needed
[OptionsBinding("Database", ValidateDataAnnotations = true, ValidateOnStart = true)]
public partial class DatabaseOptions { }[OptionsBinding("Features", Lifetime = OptionsLifetime.Monitor, OnChange = nameof(OnChanged))]
public partial class FeatureFlags
{
public bool EnableNewUI { get; set; }
internal static void OnChanged(FeatureFlags options, string? name) { }
}[OptionsBinding("Email", ChildSections = new[] { "Primary", "Secondary" }, ConfigureAll = nameof(SetDefaults))]
public partial class EmailOptions
{
public int MaxRetries { get; set; }
internal static void SetDefaults(EmailOptions o) { o.MaxRetries = 3; }
}[OptionsBinding("Storage", PostConfigure = nameof(Normalize))]
public partial class StorageOptions
{
public string BasePath { get; set; } = string.Empty;
private static void Normalize(StorageOptions o)
{
if (!o.BasePath.EndsWith(Path.DirectorySeparatorChar))
o.BasePath += Path.DirectorySeparatorChar;
}
}🏠 Home
- 💉 Working with Dependency Registration
- ⚙️ Working with Options Binding
- 🗺️ Working with Object Mapping
- 🔄 Working with Enum Mapping
- 📋 Working with Annotation Constants
- 📖 Attribute API Reference
- 🩺 Diagnostics Reference
⚠️ Common Patterns and Anti-Patterns- 🚀 Native AOT Compatibility
- 🔧 Troubleshooting
- 💉 Dependency Registration Feature Roadmap
- ⚙️ Options Binding Feature Roadmap
- 🗺️ Object Mapping Feature Roadmap
- 📋 Annotation Constants Feature Roadmap