Consider an example service that optionally supports LDAP authentication, otherwise, it does something like local Identity authentication. When LDAP is completely configured, appsettings.json might look like this...
{
"LdapOptions": {
"Host": "ldap.example.com",
"Port": 389
}
}
With an options class.
public class LdapOptions
{
public string Host { get; set; }
public int Port { get; set; } = 389;
}
And Startup has the expected Configure call.
service.Configure<LdapOptions>(nameof(LdapOptions));
This work great when I have a complete valid "LdapOptions" section. But, it's not so great if I intentionally leave the section out of my appsettings.
An IOptions<TOptions> instance resolves even if I leave the section out of my appsettings entirely; it even resolves if I remove the Startup configure call entirely! I get an object that appears, based on property values, to be default(TOptions).
public AuthenticationService(IOptions<LdapOptions> ldapOptions)
{
this.ldapOptions = ldapOptions.Value; // never null, sometimes default(LdapOptions)!
}
I don't want to depend on checking properties if a section is intentionally left out. I can imagine scenarios where all of the properties in an object have explicit defaults and this wouldn't work. I'd like something like a Maybe<TOptions> with a HasValue property, but I'll take a null.
Is there any way to make an options section optional?
Update: Be aware that I also intend to validate data annotations...
services.AddOptions<LdapOptions>()
.Configure(conf.GetSection(nameof(LdapOptions)))
.ValidateDataAnnotations();
So, what I really want is for optional options to be valid when the section is missing (conf.Exists() == false) and then normal validations to kick in when the section is partially or completely filled out.
I can't imagine any solution working with data annotation validations that depends on the behavior of creating a default instance (for example, there is no correct default for Host, so a default instance will always be invalid).