Configuration in ASP.NET Core is layered — appsettings.json, an environment-specific appsettings.{Environment}.json, environment variables, and command-line arguments are merged together, with later sources overriding earlier ones:
{
"SmtpSettings": {
"Host": "smtp.example.com",
"Port": 587
}
}
Binding a settings section to a strongly-typed class (the options pattern) is preferred over reading raw configuration strings by key scattered across the codebase:
public class SmtpSettings
{
public string Host { get; set; } = "";
public int Port { get; set; }
}
builder.Services.Configure<SmtpSettings>(builder.Configuration.GetSection("SmtpSettings"));
// Injected wherever needed, via IOptions<T> (or IOptionsSnapshot<T> for Scoped/config-reload scenarios)
class EmailSender
{
private readonly SmtpSettings _settings;
public EmailSender(IOptions<SmtpSettings> options) => _settings = options.Value;
}
IOptions<T> is registered as a singleton and reads configuration once at startup; IOptionsSnapshot<T> is scoped and re-reads configuration per request, useful when configuration can change (e.g. via a reloadable JSON file) without restarting the app. Secrets (connection strings, API keys) belong in user secrets locally and a real secret store (environment variables, Azure Key Vault, AWS Secrets Manager) in production — never committed into appsettings.json in source control.