Configuration and options

ASP.NET Core · Essentials · 12 min

Every deployed service needs environment-specific settings without code changes or committed secrets.

WebApplication.CreateBuilder loads configuration from several providers, later ones overriding earlier ones:

1. appsettings.json 2. appsettings.{Environment}.json (e.g. appsettings.Development.json) 3. User secrets (Development only, dotnet user-secrets set "Db:Password" "x") 4. Environment variables 5. Command-line arguments

Keys are hierarchical with : separators (ConnectionStrings:Main). In environment variables, use a double underscore instead: Smtp__Host=mail.local maps to Smtp:Host. This makes containers and cloud platforms easy to configure.

Read values directly with builder.Configuration["Smtp:Host"] or GetConnectionString("Main"), but prefer the options pattern: a plain class bound to a section.

builder.Services.Configure<SmtpOptions>(builder.Configuration.GetSection("Smtp"));

Then inject IOptions<SmtpOptions> (read once, singleton), IOptionsSnapshot<T> (re-read per request, scoped) or IOptionsMonitor<T> (live updates with change notifications).

Validate options at startup so bad configuration fails fast: AddOptions<SmtpOptions>().BindConfiguration("Smtp").ValidateDataAnnotations().ValidateOnStart();.

Never commit secrets to appsettings.json. Use user secrets locally and environment variables, Azure Key Vault or another secret store in production.

Example

// appsettings.json: { "Smtp": { "Host": "localhost", "Port": 25 } }
// override in production with env vars: Smtp__Host=mail.example.com
using System.ComponentModel.DataAnnotations;
using Microsoft.Extensions.Options;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOptions<SmtpOptions>()
    .BindConfiguration("Smtp")
    .ValidateDataAnnotations()
    .ValidateOnStart();                       // fail fast on bad config
var app = builder.Build();

app.MapGet("/smtp", (IOptions<SmtpOptions> opts) => $"{opts.Value.Host}:{opts.Value.Port}");
app.MapGet("/raw", (IConfiguration config) => config["Smtp:Host"] ?? "unset");

app.Run();
// GET /smtp -> localhost:25  (or mail.example.com:25 with the env var)

public class SmtpOptions
{
    [Required] public string Host { get; set; } = "";
    [Range(1, 65535)] public int Port { get; set; } = 25;
}

Remember

  • Later providers override earlier ones: JSON, env-specific JSON, secrets, env vars, command line
  • Use __ in environment variable names for nested keys
  • Bind sections to classes with the options pattern
  • Validate options on start; keep secrets out of source control

Watch out for

  • Committing production passwords in appsettings.json.

Check yourself

  1. Which environment variable sets the configuration key Logging:LogLevel:Default?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/