Configuration & Options
Posted on August 21st, 2022
Part of Notes on .NET
Talks aboutC#.NET
Configuration functionality comes from the Microsoft.Extensions.Configuration package.Data is accessed using key-value pairs; nested keys are separated with colons (e.g., Section1:Key1).
Simple access to keys and values uses get methods:
IConfiguration config = null;
// Value access
config.GetValue<bool>("SomeBool");
// Nested values
config.GetValue<string>("NestedBool:AnotherBool");
// Section scope
var faveDrinks = config.GetSection("Favourites:Drinks");
var faveHotDrink = faveDrinks.GetValue<string>("Hot");Storing connection strings under the ConnectionStrings key is a common pattern;
GetConnectionString(cs) method automatically checks for a string under the
ConnectionStrings key.
Configuration Sources
appsettings.json is the default configuration file used by .NET.Environment-specific
files can override the base config file; e.g., appsettings.Development.json
or appsettings.Staging.json.
Similarly, Visual Studio has a  launchSettings.json which uses
__ as its hierarchy spacer.
Environment variables can overwrite values further: $Favourites__Food=Banana.
Finally, command-line arguments can also be used:$ dotnet run --Favourites:Food Banana
Security
Storing secure data in files is bad as they either live in source control or on
deployment platforms. Dotnet provides user-secrets to store secure data at
development-time instead: $ dotnet user-secrets set "Favourites:Food" "Banana".
For production, Azure Key Vault can be implemented with the
Microsoft.Azure.Services.AppAuthentication and
Microsoft.Extensions.Configuration.AzureKeyVault packages.
Options Pattern
Although IConfiguration can be injected, using getters with magic
string/static constant strings isn't ideal. The Options pattern is much cleaner
and robust, using models matching the structure of configuration data.
public class AuthOptions
{
  public TimeSpan CookieLifeTime { get; set; }
}
services.Configure<AuthOptions>(configuration.GetSection("Auth"));Live Updates
The standard Configure method registers a singleton. Alternatively, the
IOptionsSnapshot<> interface registers configs as scoped dependencies which
provides the latest configuration data on construction.
For the latest data every time, use the CurrentValue property offered by IOptionsMonitor<>.
Validation
The extension method ValidateDataAnnotations() can validate configuration files
against attributes like [Required].
Note: validation is triggered on the first access to the object, not on creation, so be smart when using this.