This episode teaches correct application configuration in .NET: the options pattern and binding to POCOs, per-environment files, secrets management, JSON, env var and command line providers, and strongly typed configuration with validation.

Every application needs settings: database connections, API keys, feature flags. Episode 10 covers how to manage all of this correctly in .NET — from the strongly typed options pattern, to per-environment files, to secure secrets management.
The problems this episode solves are real: configuration scattered across code is hard to change without a rebuild, and secrets committed to Git are a ticking time bomb. With the .NET configuration system, you separate code from settings and let the environment determine the values.
Instead of reading keys one by one, bind a group of settings to a POCO:
public class SmtpOptions
{
public string Host { get; set; }
public int Port { get; set; }
public bool UseTls { get; set; }
}The SmtpOptions class maps to the Smtp configuration section. C# properties are mapped automatically from keys with matching casing — host, port, and useTls.
Binding happens at service registration:
builder.Services.AddOptions<SmtpOptions>()
.Bind(builder.Configuration.GetSection("Smtp"))
.ValidateDataAnnotations();builder.Configuration.GetSection("Smtp") takes the Smtp section from appsettings, then binds it to SmtpOptions. With the options pattern, services receive IOptions<SmtpOptions> or IOptionsMonitor<SmtpOptions> and get typed configuration.
The host loads appsettings.json for all environments, then appsettings.{Environment}.json for the specific one:
{
"Smtp": {
"Host": "localhost",
"Port": 1025,
"UseTls": false
}
}When ASPNETCORE_ENVIRONMENT=Development, the Smtp:Host value comes from the Development file. The host name is set via the ASPNETCORE_ENVIRONMENT variable (web) or DOTNET_ENVIRONMENT (worker). Per-environment files go into Git because they contain no secrets.
API keys and tokens must not live in committed JSON files. Use User Secrets during local development:
dotnet user-secrets init
dotnet user-secrets set "Smtp:Host" "smtp.provider.com"dotnet user-secrets set "Smtp:Host" "smtp.provider.com" stores the value outside the project — in a user profile file that never enters Git. For production, use environment variables or a cloud secret manager (episode 19).
The .NET configuration system is composable: many providers are read in sequence, and later providers override earlier ones. The default host order:
appsettings.jsonappsettings.{Environment}.jsondotnet run -- --Smtp:Host smtp.lain.com--Smtp:Host smtp.lain.com overrides the value from the command line — useful for quick testing without changing files.
Environment variables use __ as the section separator: Smtp__Host maps to Smtp:Host. An example:
export Smtp__Host="smtp.provider.com"Because env vars are the last provider before the command line, this value wins over the JSON files. This is the main way to inject configuration when deploying to containers.
Wrong configuration should fail at startup, not at runtime:
public class SmtpOptions
{
[Required]
public string Host { get; set; }
[Range(1, 65535)]
public int Port { get; set; }
public bool UseTls { get; set; }
}The [Required] and [Range] attributes validate the values after binding. If validation fails, the application throws an error at startup — far better than processing emails with an empty host.
IOptionsMonitor<T> reads the latest values when a configuration file changes without a restart:
public class MailService
{
private readonly IOptionsMonitor<SmtpOptions> _opsi;
public MailService(IOptionsMonitor<SmtpOptions> opsi)
{
_opsi = opsi;
}
public string Host => _opsi.CurrentValue.Host;
}_opsi.CurrentValue.Host always holds the latest value. Use IOptions<T> for static values at startup, and IOptionsMonitor<T> for settings that need to be reloaded.
Warning
Never write secrets to logs or API responses. Configuration validation makes sure mistakes are caught early, but staying careful about printing the values remains your responsibility.
Key takeaways:
appsettings.{Environment}.json files separate values per environment.In the next episode 11 we will discuss web API and HTTP client — the basics of ASP.NET Core Web API, controllers, routing, model binding, and response formatting, Minimal APIs, and using an HTTP client with resilience patterns.