[{"data":1,"prerenderedAt":110},["ShallowReactive",2],{"qa-\u002Fdotnet\u002Faspnet-core\u002Fconfiguration":3},{"page":4,"siblings":94,"blog":107},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"questionsCount":85,"related":86,"seo":87,"seoDescription":88,"stem":89,"subtopic":6,"topic":90,"topicSlug":91,"updated":92,"__hash__":93},"qa\u002Fdotnet\u002Faspnet-core\u002Fconfiguration.md","Configuration",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md",".NET Core","dotnet",{},true,4,"\u002Fdotnet\u002Faspnet-core\u002Fconfiguration",[23,28,32,36,40,44,48,52,56,61,65,69,73,77,81],{"id":24,"difficulty":25,"q":26,"a":27},"configuration-what-is","easy","What is the ASP.NET Core configuration system and how does it work?","The ASP.NET Core **configuration system** aggregates key-value pairs from multiple\n**configuration providers** into a unified `IConfiguration` interface. Providers are\nlayered — later providers override earlier ones for the same key.\n\n```csharp\n\u002F\u002F Default provider order (WebApplication.CreateBuilder):\n\u002F\u002F 1. appsettings.json\n\u002F\u002F 2. appsettings.{Environment}.json (e.g., appsettings.Production.json)\n\u002F\u002F 3. User Secrets (Development only)\n\u002F\u002F 4. Environment variables\n\u002F\u002F 5. Command-line arguments\n\nvar builder = WebApplication.CreateBuilder(args);\n\u002F\u002F builder.Configuration is already populated from the sources above\n\n\u002F\u002F Read a value:\nstring? conn = builder.Configuration[\"ConnectionStrings:DefaultConnection\"];\n\u002F\u002F or via GetConnectionString shortcut:\nstring? conn2 = builder.Configuration.GetConnectionString(\"DefaultConnection\");\n\n\u002F\u002F Read a section:\nIConfigurationSection mailSection = builder.Configuration.GetSection(\"Mail\");\nstring? host = mailSection[\"Host\"];\nint port = mailSection.GetValue\u003Cint>(\"Port\", defaultValue: 587);\n```\n\n`appsettings.json`:\n```json\n{\n  \"ConnectionStrings\": {\n    \"DefaultConnection\": \"Server=.;Database=MyDb;Trusted_Connection=True\"\n  },\n  \"Mail\": {\n    \"Host\": \"smtp.example.com\",\n    \"Port\": 587\n  }\n}\n```\n\n**Rule of thumb:** Never hard-code secrets or environment-specific values in code.\nUse the configuration system so values can be overridden per environment through\nappsettings files, environment variables, or secrets management tools.\n",{"id":29,"difficulty":25,"q":30,"a":31},"configuration-providers","What are the built-in configuration providers and how are they ordered?","ASP.NET Core supports many built-in providers. `WebApplication.CreateBuilder` sets up\nthe default stack automatically; you can customize with `ConfigureAppConfiguration`.\n\n```csharp\n\u002F\u002F Default stack — later entries WIN (override earlier):\n\u002F\u002F appsettings.json → appsettings.{Env}.json → User Secrets → Env vars → CLI args\n\n\u002F\u002F Customizing the stack:\nbuilder.Configuration\n    \u002F\u002F 1. Clear existing providers:\n    .Sources.Clear();\n\nbuilder.Host.ConfigureAppConfiguration((ctx, config) =>\n{\n    config.AddJsonFile(\"appsettings.json\", optional: false, reloadOnChange: true);\n    config.AddJsonFile(\n        $\"appsettings.{ctx.HostingEnvironment.EnvironmentName}.json\",\n        optional: true,\n        reloadOnChange: true);\n\n    if (ctx.HostingEnvironment.IsDevelopment())\n        config.AddUserSecrets\u003CProgram>(); \u002F\u002F safe dev-only secrets\n\n    config.AddEnvironmentVariables(prefix: \"MYAPP_\"); \u002F\u002F MYAPP_Mail__Host → Mail:Host\n\n    config.AddCommandLine(args); \u002F\u002F --Mail:Host=smtp.example.com\n\n    \u002F\u002F Custom: Azure Key Vault (requires Azure.Extensions.AspNetCore.Configuration.Secrets):\n    \u002F\u002F config.AddAzureKeyVault(new Uri(\"https:\u002F\u002Fmyvault.vault.azure.net\u002F\"), new DefaultAzureCredential());\n\n    \u002F\u002F Custom: AWS Secrets Manager, HashiCorp Vault, etc.\n});\n```\n\nEnvironment variable key mapping:\n- Double underscore `__` maps to `:` (section separator).\n- `MYAPP_Mail__Host` → `Mail:Host`\n- `MYAPP_ConnectionStrings__DefaultConnection` → `ConnectionStrings:DefaultConnection`\n\n**Rule of thumb:** For secrets (API keys, connection strings), use User Secrets in\ndevelopment and environment variables \u002F a secrets manager (Azure Key Vault, AWS\nSecrets Manager) in production — never commit secrets to `appsettings.json`.\n",{"id":33,"difficulty":14,"q":34,"a":35},"ioptions","What is the Options pattern (`IOptions\u003CT>`, `IOptionsSnapshot\u003CT>`, `IOptionsMonitor\u003CT>`) and when do you use each?","The **Options pattern** binds a configuration section to a strongly-typed class and\ninjects it via DI. Three interfaces serve different lifetime \u002F reload needs:\n\n- **`IOptions\u003CT>`** — singleton; reads config once at startup; does **not** see changes.\n- **`IOptionsSnapshot\u003CT>`** — scoped; re-reads config **once per request**; sees\n  reloaded values from the next request onward.\n- **`IOptionsMonitor\u003CT>`** — singleton; sees config changes **immediately** via a\n  change-notification callback.\n\n```csharp\n\u002F\u002F POCO:\npublic class MailOptions\n{\n    public const string SectionName = \"Mail\";\n    public string Host { get; set; } = default!;\n    public int Port { get; set; } = 587;\n    public bool UseSsl { get; set; } = true;\n}\n\n\u002F\u002F Register:\nbuilder.Services.Configure\u003CMailOptions>(\n    builder.Configuration.GetSection(MailOptions.SectionName));\n\n\u002F\u002F Inject and use:\npublic class EmailService\n{\n    private readonly MailOptions _opts;\n\n    \u002F\u002F IOptions\u003CT> — fixed at startup (singleton):\n    public EmailService(IOptions\u003CMailOptions> opts) =>\n        _opts = opts.Value;\n\n    \u002F\u002F IOptionsSnapshot\u003CT> — re-read per request (scoped service):\n    public EmailService(IOptionsSnapshot\u003CMailOptions> opts) =>\n        _opts = opts.Value;\n\n    \u002F\u002F IOptionsMonitor\u003CT> — live updates (singleton service):\n    public EmailService(IOptionsMonitor\u003CMailOptions> monitor)\n    {\n        _opts = monitor.CurrentValue;\n        monitor.OnChange(newValue =>\n        {\n            \u002F\u002F Called whenever config changes on disk\n            Console.WriteLine($\"Config changed: Host={newValue.Host}\");\n        });\n    }\n}\n```\n\n| Interface | Lifetime | Sees reloads? | Best for |\n|---|---|---|---|\n| `IOptions\u003CT>` | Singleton | No | Startup-only config, singletons |\n| `IOptionsSnapshot\u003CT>` | Scoped | Per-request | Web requests, feature flags |\n| `IOptionsMonitor\u003CT>` | Singleton | Immediately | Long-running services, background workers |\n\n**Rule of thumb:** Use `IOptions\u003CT>` for configuration that never changes at\nruntime. Use `IOptionsSnapshot\u003CT>` in request-scoped services when you want\nper-request config refresh. Use `IOptionsMonitor\u003CT>` in singletons or background\nservices that need live config updates without restart.\n",{"id":37,"difficulty":14,"q":38,"a":39},"options-validation","How do you validate configuration options at startup to fail fast on bad config?","ASP.NET Core lets you validate Options at startup using Data Annotations,\n`IValidateOptions\u003CT>`, or the fluent `Validate` overload.\n\n```csharp\n\u002F\u002F Data Annotations on the POCO:\npublic class SmtpOptions\n{\n    [Required]\n    public string Host { get; set; } = default!;\n\n    [Range(1, 65535)]\n    public int Port { get; set; }\n\n    [Required, EmailAddress]\n    public string FromAddress { get; set; } = default!;\n}\n\n\u002F\u002F Register with annotation validation + eager validation at startup:\nbuilder.Services\n    .AddOptions\u003CSmtpOptions>()\n    .BindConfiguration(\"Smtp\")\n    .ValidateDataAnnotations()\n    .ValidateOnStart(); \u002F\u002F throws on startup instead of first use!\n\n\u002F\u002F Custom validation:\nbuilder.Services\n    .AddOptions\u003CSmtpOptions>()\n    .BindConfiguration(\"Smtp\")\n    .Validate(opts =>\n    {\n        if (opts.Port == 25 && opts.Host.EndsWith(\".example.com\"))\n            return false; \u002F\u002F invalid combination\n        return true;\n    }, \"Port 25 is not allowed for example.com SMTP servers\")\n    .ValidateOnStart();\n```\n\nWithout `ValidateOnStart()`, validation runs on first access of `.Value`. With it,\nbad config causes the app to refuse to start — a much better failure mode.\n\n**Rule of thumb:** Always add `.ValidateDataAnnotations().ValidateOnStart()` to\nany critical options binding. Failing fast at startup is far better than a\nproduction runtime error when a feature is first exercised.\n",{"id":41,"difficulty":14,"q":42,"a":43},"user-secrets","What are User Secrets and how do you use them in development?","**User Secrets** store sensitive config values (API keys, connection strings) outside\nthe project directory during development, so they are never committed to source\ncontrol. They are stored in `%APPDATA%\\Microsoft\\UserSecrets\\\u003Cid>\\secrets.json`\n(Windows) or `~\u002F.microsoft\u002Fusersecrets\u002F\u003Cid>\u002Fsecrets.json` (Linux\u002FmacOS).\n\n```bash\n# Initialize user secrets for the project (adds \u003CUserSecretsId> to .csproj):\ndotnet user-secrets init\n\n# Set secrets:\ndotnet user-secrets set \"ConnectionStrings:DefaultConnection\" \"Server=.;...\"\ndotnet user-secrets set \"Stripe:SecretKey\" \"sk_test_abc123\"\ndotnet user-secrets set \"Mail:Password\" \"my-smtp-password\"\n\n# List all secrets:\ndotnet user-secrets list\n\n# Remove a secret:\ndotnet user-secrets remove \"Mail:Password\"\n```\n\nThey are automatically loaded in the `Development` environment by\n`WebApplication.CreateBuilder`:\n\n```csharp\n\u002F\u002F Automatically added in Development:\nif (app.Environment.IsDevelopment())\n    builder.Configuration.AddUserSecrets\u003CProgram>();\n\n\u002F\u002F WebApplication.CreateBuilder does this by default — you usually don't need to call it manually.\n\n\u002F\u002F Access normally via IConfiguration:\nvar key = builder.Configuration[\"Stripe:SecretKey\"];\n```\n\nIn production, use environment variables or a secrets manager — User Secrets are\na **development-only** mechanism.\n\n**Rule of thumb:** Use User Secrets for any credential a dev needs locally but\nmust not check in. Never add `secrets.json` to `.gitignore` — it's outside the\nrepo directory by design.\n",{"id":45,"difficulty":25,"q":46,"a":47},"environment-specific-config","How does ASP.NET Core handle environment-specific configuration?","The **hosting environment** (`ASPNETCORE_ENVIRONMENT` env var) controls which\n`appsettings.{Environment}.json` file is loaded. The environment-specific file\n**merges with and overrides** values from `appsettings.json`.\n\n```json\n\u002F\u002F appsettings.json (base — checked into source control):\n{\n  \"Logging\": { \"LogLevel\": { \"Default\": \"Warning\" } },\n  \"FeatureFlags\": { \"NewCheckout\": false },\n  \"ConnectionStrings\": { \"DefaultConnection\": \"\" }\n}\n\n\u002F\u002F appsettings.Development.json (local overrides — can be committed for shared dev):\n{\n  \"Logging\": { \"LogLevel\": { \"Default\": \"Debug\" } },\n  \"FeatureFlags\": { \"NewCheckout\": true }\n}\n\n\u002F\u002F appsettings.Production.json (minimal; secrets come from env vars):\n{\n  \"Logging\": { \"LogLevel\": { \"Default\": \"Error\" } }\n}\n```\n\n```csharp\n\u002F\u002F Check environment in code:\nif (app.Environment.IsDevelopment())\n    app.UseDeveloperExceptionPage();\nelse\n    app.UseExceptionHandler(\"\u002Ferror\");\n\n\u002F\u002F Custom environments:\n\u002F\u002F ASPNETCORE_ENVIRONMENT=Staging → loads appsettings.Staging.json\nif (app.Environment.IsEnvironment(\"Staging\"))\n    EnableStagingFeatures();\n```\n\n`IWebHostEnvironment` (injected via DI) exposes:\n- `EnvironmentName` — the string value\n- `IsDevelopment()`, `IsStaging()`, `IsProduction()` — convenience methods\n- `ContentRootPath`, `WebRootPath`\n\n**Rule of thumb:** Keep `appsettings.json` free of secrets and environment-specific\nvalues. Use `appsettings.{Env}.json` for non-secret environment differences. Put\nsecrets in environment variables or a secrets manager, not in any config file that\ngets committed.\n",{"id":49,"difficulty":14,"q":50,"a":51},"iconfiguration-bind","How do you use `IConfiguration.Bind`, `Get\u003CT>`, and `GetSection` to read config?","`IConfiguration` provides several methods to read values: `GetValue\u003CT>`, `GetSection`,\n`Bind`, and `Get\u003CT>`.\n\n```csharp\n\u002F\u002F appsettings.json:\n\u002F\u002F {\n\u002F\u002F \"App\": { \"Name\": \"MyApp\", \"MaxItems\": 100, \"Tags\": [\"api\",\"web\"] }\n\u002F\u002F }\n\n\u002F\u002F GetValue\u003CT> — read a single value with optional default:\nstring name     = config.GetValue\u003Cstring>(\"App:Name\") ?? \"Default\";\nint maxItems    = config.GetValue\u003Cint>(\"App:MaxItems\", defaultValue: 50);\n\n\u002F\u002F GetSection — get a sub-section (does NOT throw if missing):\nIConfigurationSection appSection = config.GetSection(\"App\");\nstring? sectionName = appSection[\"Name\"]; \u002F\u002F \"MyApp\"\n\n\u002F\u002F Bind — populate an existing object from config:\nvar opts = new AppOptions();\nconfig.GetSection(\"App\").Bind(opts);\n\u002F\u002F opts.Name == \"MyApp\", opts.MaxItems == 100\n\n\u002F\u002F Get\u003CT> — returns a new instance of T bound from the section:\nAppOptions opts2 = config.GetSection(\"App\").Get\u003CAppOptions>()!;\n\n\u002F\u002F Bind arrays:\nstring[] tags = config.GetSection(\"App:Tags\").Get\u003Cstring[]>()!;\n\u002F\u002F tags == [\"api\", \"web\"]\n\npublic class AppOptions\n{\n    public string Name { get; set; } = default!;\n    public int MaxItems { get; set; }\n    public List\u003Cstring> Tags { get; set; } = new();\n}\n```\n\n`GetSection(\"missing\")` returns an empty `IConfigurationSection` (not null) —\ncheck `section.Exists()` before using it:\n\n```csharp\nvar section = config.GetSection(\"FeatureFlags\");\nif (section.Exists())\n    section.Bind(featureFlags);\n```\n\n**Rule of thumb:** Prefer the Options pattern (`IOptions\u003CT>`) over directly calling\n`IConfiguration` in application services — it gives you DI, validation, and reload\nsupport. Use `IConfiguration` directly only in startup code or simple console apps.\n",{"id":53,"difficulty":14,"q":54,"a":55},"configuration-reload","Does ASP.NET Core automatically reload configuration when `appsettings.json` changes?","Yes — by default, `AddJsonFile` is registered with `reloadOnChange: true`, so\n`appsettings.json` and `appsettings.{Env}.json` are re-read when the file changes\non disk (via `FileSystemWatcher`). `IConfiguration` and `IOptionsMonitor\u003CT>` reflect\nthe new values immediately; `IOptionsSnapshot\u003CT>` reflects them on the next request;\n`IOptions\u003CT>` **never** reloads.\n\n```csharp\n\u002F\u002F Reload is on by default — this is what WebApplication.CreateBuilder does:\nconfig.AddJsonFile(\"appsettings.json\", optional: false, reloadOnChange: true);\nconfig.AddJsonFile($\"appsettings.{env}.json\", optional: true, reloadOnChange: true);\n\n\u002F\u002F IOptionsMonitor: subscribes to live changes\npublic class FeatureFlagService\n{\n    private readonly IOptionsMonitor\u003CFeatureOptions> _monitor;\n    public FeatureFlagService(IOptionsMonitor\u003CFeatureOptions> monitor)\n        => _monitor = monitor;\n\n    public bool IsEnabled(string flag)\n        => _monitor.CurrentValue.EnabledFlags.Contains(flag); \u002F\u002F always fresh\n}\n\n\u002F\u002F IOptionsSnapshot: fresh per-request (scoped services)\npublic class RequestHandler\n{\n    private readonly FeatureOptions _opts;\n    public RequestHandler(IOptionsSnapshot\u003CFeatureOptions> opts)\n        => _opts = opts.Value; \u002F\u002F bound once per request scope\n}\n\n\u002F\u002F IOptions: frozen at startup (no reload)\npublic class CachedService\n{\n    private readonly FeatureOptions _opts;\n    public CachedService(IOptions\u003CFeatureOptions> opts)\n        => _opts = opts.Value; \u002F\u002F static — never changes\n}\n```\n\n**Rule of thumb:** Use `IOptionsMonitor\u003CT>` in singletons or background workers\nthat need live config without a restart. In production, use reload carefully for\ncritical values — an invalid config file mid-flight can crash the app or produce\nunexpected behavior.\n",{"id":57,"difficulty":58,"q":59,"a":60},"named-options","hard","What are named options and when do you use them?","**Named options** allow multiple instances of the same options class, each configured\ndifferently. They are useful when you have multiple instances of a service with\ndifferent configuration (e.g., two SMTP servers, multiple HTTP clients).\n\n```csharp\n\u002F\u002F Two SMTP configurations in appsettings.json:\n\u002F\u002F {\n\u002F\u002F \"Smtp\": {\n\u002F\u002F \"Transactional\": { \"Host\": \"smtp1.example.com\", \"Port\": 587 },\n\u002F\u002F \"Marketing\":     { \"Host\": \"smtp2.example.com\", \"Port\": 465 }\n\u002F\u002F }\n\u002F\u002F }\n\n\u002F\u002F Register named options:\nbuilder.Services.Configure\u003CSmtpOptions>(\"Transactional\",\n    builder.Configuration.GetSection(\"Smtp:Transactional\"));\nbuilder.Services.Configure\u003CSmtpOptions>(\"Marketing\",\n    builder.Configuration.GetSection(\"Smtp:Marketing\"));\n\n\u002F\u002F Inject and resolve by name:\npublic class EmailDispatcher\n{\n    private readonly SmtpOptions _transactional;\n    private readonly SmtpOptions _marketing;\n\n    public EmailDispatcher(IOptionsMonitor\u003CSmtpOptions> monitor)\n    {\n        _transactional = monitor.Get(\"Transactional\");\n        _marketing     = monitor.Get(\"Marketing\");\n    }\n\n    public void SendTransactional(string to, string body)\n        => Send(_transactional, to, body);\n\n    public void SendMarketing(string to, string body)\n        => Send(_marketing, to, body);\n}\n```\n\n`IHttpClientFactory` uses named options internally:\n\n```csharp\nbuilder.Services.AddHttpClient(\"github\", client =>\n{\n    client.BaseAddress = new Uri(\"https:\u002F\u002Fapi.github.com\u002F\");\n    client.DefaultRequestHeaders.Add(\"User-Agent\", \"MyApp\");\n});\n\n\u002F\u002F Inject named client:\nvar client = httpClientFactory.CreateClient(\"github\");\n```\n\n**Rule of thumb:** Use named options when you need multiple configurations for the\nsame options type — commonly for HTTP clients, SMTP servers, external service\nendpoints, or feature flag namespaces.\n",{"id":62,"difficulty":58,"q":63,"a":64},"post-configure","What is `PostConfigure` and how does it differ from `Configure`?","**`Configure\u003CT>`** sets up options values. **`PostConfigure\u003CT>`** runs *after all\n`Configure` registrations* for the same type — it is the last step and can override\nor validate values set by earlier `Configure` calls or by third-party libraries.\n\n```csharp\n\u002F\u002F Scenario: override a value set by an external library's Configure call\n\n\u002F\u002F External library registers its defaults:\nbuilder.Services.Configure\u003CCacheOptions>(opts =>\n{\n    opts.MaxSize = 100;\n    opts.Expiry  = TimeSpan.FromMinutes(10);\n});\n\n\u002F\u002F Your code runs AFTER — PostConfigure:\nbuilder.Services.PostConfigure\u003CCacheOptions>(opts =>\n{\n    \u002F\u002F Runs after ALL Configure calls for CacheOptions\n    if (opts.MaxSize > 500)\n        opts.MaxSize = 500; \u002F\u002F enforce a cap regardless of what lib set\n});\n\n\u002F\u002F PostConfigureAll — applies to ALL named instances:\nbuilder.Services.PostConfigureAll\u003CSmtpOptions>(opts =>\n    opts.UseSsl = true); \u002F\u002F enforce SSL on every named SMTP config\n```\n\nExecution order for options pipeline:\n1. All `Configure\u003CT>` calls (in registration order)\n2. All `PostConfigure\u003CT>` calls (in registration order)\n3. `IValidateOptions\u003CT>` validators\n\n```csharp\n\u002F\u002F Confirm ordering with a simple example:\nbuilder.Services.Configure\u003CMyOpts>(o => o.Value = \"first\");\nbuilder.Services.Configure\u003CMyOpts>(o => o.Value = \"second\");\nbuilder.Services.PostConfigure\u003CMyOpts>(o => o.Value = \"post\"); \u002F\u002F wins\n\u002F\u002F Result: opts.Value == \"post\"\n```\n\n**Rule of thumb:** Use `PostConfigure` when you need to enforce global constraints\non options that third-party libraries configure, or when you need a guaranteed\n\"last word\" on a value regardless of other configuration sources.\n",{"id":66,"difficulty":14,"q":67,"a":68},"config-in-non-web","How do you use the ASP.NET Core configuration system in a console app or background service?","The configuration system is part of `Microsoft.Extensions.Configuration` and works\nin any .NET app — not just ASP.NET Core. Use `Host.CreateDefaultBuilder` or the\nnewer `Host.CreateApplicationBuilder` to get the same provider stack.\n\n```csharp\n\u002F\u002F Worker service \u002F console app:\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nvar host = Host.CreateDefaultBuilder(args)\n    .ConfigureAppConfiguration((ctx, config) =>\n    {\n        \u002F\u002F Same providers as WebApplication.CreateBuilder:\n        config.AddJsonFile(\"appsettings.json\", optional: false, reloadOnChange: true);\n        config.AddJsonFile($\"appsettings.{ctx.HostingEnvironment.EnvironmentName}.json\",\n            optional: true);\n        config.AddEnvironmentVariables();\n        if (ctx.HostingEnvironment.IsDevelopment())\n            config.AddUserSecrets\u003CProgram>();\n    })\n    .ConfigureServices((ctx, services) =>\n    {\n        services.Configure\u003CWorkerOptions>(ctx.Configuration.GetSection(\"Worker\"));\n        services.AddHostedService\u003CMyWorker>();\n    })\n    .Build();\n\nawait host.RunAsync();\n\n\u002F\u002F Background service receives options via DI:\npublic class MyWorker : BackgroundService\n{\n    private readonly WorkerOptions _opts;\n    public MyWorker(IOptions\u003CWorkerOptions> opts) => _opts = opts.Value;\n\n    protected override async Task ExecuteAsync(CancellationToken ct)\n    {\n        while (!ct.IsCancellationRequested)\n        {\n            DoWork(_opts.IntervalSeconds);\n            await Task.Delay(TimeSpan.FromSeconds(_opts.IntervalSeconds), ct);\n        }\n    }\n}\n```\n\n**Rule of thumb:** Use `Host.CreateDefaultBuilder` or `Host.CreateApplicationBuilder`\nin console apps and background services to get the same configuration, logging, and\nDI infrastructure as ASP.NET Core — avoid reinventing it with manual provider setup.\n",{"id":70,"difficulty":58,"q":71,"a":72},"iconfigure-options","What is `IConfigureOptions\u003CT>` and how does it differ from `services.Configure\u003CT>`?","**`IConfigureOptions\u003CT>`** is an interface that lets you encapsulate options\nconfiguration logic in a dedicated class, which is itself resolved from DI.\nThis is useful when the configuration logic requires services (e.g., reading from\na database or calling an API) that are not available during the `Configure` delegate.\n\n```csharp\n\u002F\u002F Plain Configure\u003CT> — closure-based, no DI services available:\nbuilder.Services.Configure\u003CJwtOptions>(opts =>\n{\n    opts.Secret = builder.Configuration[\"Jwt:Secret\"]!;\n    \u002F\u002F Cannot inject ISomeService here — DI is not yet built\n});\n\n\u002F\u002F IConfigureOptions\u003CT> — runs after DI is built; can inject services:\npublic class JwtOptionsConfigurator : IConfigureOptions\u003CJwtOptions>\n{\n    private readonly IConfiguration _config;\n    private readonly ISecretVaultService _vault;\n\n    \u002F\u002F Dependencies resolved from the built DI container:\n    public JwtOptionsConfigurator(IConfiguration config, ISecretVaultService vault)\n    {\n        _config = config;\n        _vault  = vault;\n    }\n\n    public void Configure(JwtOptions options)\n    {\n        options.Issuer   = _config[\"Jwt:Issuer\"]!;\n        options.Audience = _config[\"Jwt:Audience\"]!;\n        \u002F\u002F Fetch secret from vault — possible because this runs post-DI-build:\n        options.Secret   = _vault.GetSecret(\"jwt-signing-key\");\n    }\n}\n\n\u002F\u002F Register the configurator as a DI service:\nbuilder.Services.AddSingleton\u003CIConfigureOptions\u003CJwtOptions>, JwtOptionsConfigurator>();\n\n\u002F\u002F IPostConfigureOptions\u003CT> — same pattern but runs after all Configure calls:\npublic class JwtPostConfigurator : IPostConfigureOptions\u003CJwtOptions>\n{\n    public void PostConfigure(string? name, JwtOptions options)\n    {\n        if (string.IsNullOrEmpty(options.Secret))\n            throw new InvalidOperationException(\"JWT secret must be configured\");\n    }\n}\nbuilder.Services.AddSingleton\u003CIPostConfigureOptions\u003CJwtOptions>, JwtPostConfigurator>();\n```\n\n**Rule of thumb:** Use `services.Configure\u003CT>` for simple config binding from\n`IConfiguration`. Use `IConfigureOptions\u003CT>` when configuration requires injected\nservices (vault clients, DB lookups, computed values) — it runs after the container\nis fully built and gives you access to the complete DI graph.\n",{"id":74,"difficulty":58,"q":75,"a":76},"azure-key-vault-config","How do you integrate Azure Key Vault as a configuration provider in ASP.NET Core?","Azure Key Vault is added as a configuration provider using\n`Azure.Extensions.AspNetCore.Configuration.Secrets`. Secrets are loaded alongside\n`appsettings.json` and accessible through the standard `IConfiguration` interface.\n\n```csharp\n\u002F\u002F Package: Azure.Extensions.AspNetCore.Configuration.Secrets\n\u002F\u002F          Azure.Identity\n\nusing Azure.Identity;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n\u002F\u002F Add Key Vault as a configuration source (production pattern):\nif (!builder.Environment.IsDevelopment())\n{\n    var keyVaultUri = new Uri(builder.Configuration[\"KeyVault:Uri\"]!);\n\n    \u002F\u002F DefaultAzureCredential: tries Managed Identity, then az login, etc.\n    builder.Configuration.AddAzureKeyVault(\n        keyVaultUri,\n        new DefaultAzureCredential());\n}\n\n\u002F\u002F Secrets are available via IConfiguration using -- as the key separator:\n\u002F\u002F Key Vault secret \"ConnectionStrings--DefaultConnection\"\n\u002F\u002F   → accessible as Configuration[\"ConnectionStrings:DefaultConnection\"]\n\n\u002F\u002F Access via Options pattern (preferred):\nbuilder.Services.Configure\u003CDbOptions>(builder.Configuration.GetSection(\"ConnectionStrings\"));\n\n\u002F\u002F Key Vault secret naming conventions:\n\u002F\u002F \"Mail--Host\"     → Mail:Host\n\u002F\u002F \"Jwt--Secret\"    → Jwt:Secret\n\u002F\u002F Named version:   \"Mail--Smtp1--Host\" → Mail:Smtp1:Host\n\n\u002F\u002F Prefix filtering — only load secrets starting with \"MyApp-\":\nbuilder.Configuration.AddAzureKeyVault(\n    keyVaultUri,\n    new DefaultAzureCredential(),\n    new AzureKeyVaultConfigurationOptions\n    {\n        Manager = new KeyVaultSecretManager() \u002F\u002F custom: override to filter\u002Frename keys\n    });\n```\n\nKey Vault secrets are fetched once at startup (no reload by default). Enable polling:\n\n```csharp\nnew AzureKeyVaultConfigurationOptions\n{\n    ReloadInterval = TimeSpan.FromMinutes(30) \u002F\u002F re-fetch secrets every 30 min\n}\n```\n\n**Rule of thumb:** In production, replace User Secrets and env-var secrets with\nAzure Key Vault. Use `DefaultAzureCredential` so the same code works with Managed\nIdentity in Azure and with `az login` locally. Never store Key Vault URIs or\ncredentials in `appsettings.json`.\n",{"id":78,"difficulty":14,"q":79,"a":80},"config-in-tests","How do you override configuration values in integration tests?","When using `WebApplicationFactory\u003CT>` for integration tests, you can override\nconfiguration via `ConfigureAppConfiguration` in a custom factory, or by setting\nenvironment variables before the test host starts.\n\n```csharp\nusing Microsoft.AspNetCore.Mvc.Testing;\nusing Microsoft.Extensions.Configuration;\n\n\u002F\u002F Custom factory that overrides configuration for tests:\npublic class TestWebApplicationFactory : WebApplicationFactory\u003CProgram>\n{\n    protected override void ConfigureWebHost(IWebHostBuilder builder)\n    {\n        builder.ConfigureAppConfiguration((ctx, config) =>\n        {\n            \u002F\u002F Add in-memory config — overrides appsettings.json (added later = wins):\n            config.AddInMemoryCollection(new Dictionary\u003Cstring, string?>\n            {\n                [\"ConnectionStrings:DefaultConnection\"] = \"DataSource=:memory:\",\n                [\"Mail:Host\"]     = \"localhost\",\n                [\"Mail:Port\"]     = \"1025\",\n                [\"FeatureFlags:NewCheckout\"] = \"true\",\n                [\"Jwt:Secret\"]    = \"test-only-signing-key-minimum-32-chars!!\"\n            });\n        });\n\n        \u002F\u002F Also swap out services for test doubles:\n        builder.ConfigureServices(services =>\n        {\n            \u002F\u002F Replace real DB with in-memory:\n            services.RemoveAll\u003CDbContextOptions\u003CAppDb>>();\n            services.AddDbContext\u003CAppDb>(o => o.UseInMemoryDatabase(\"TestDb\"));\n        });\n    }\n}\n\n\u002F\u002F Test class:\npublic class OrdersApiTests : IClassFixture\u003CTestWebApplicationFactory>\n{\n    private readonly HttpClient _client;\n\n    public OrdersApiTests(TestWebApplicationFactory factory)\n        => _client = factory.CreateClient();\n\n    [Fact]\n    public async Task GetOrders_ReturnsOk()\n    {\n        var response = await _client.GetAsync(\"\u002Fapi\u002Forders\");\n        response.EnsureSuccessStatusCode();\n    }\n}\n```\n\n**Rule of thumb:** Use `AddInMemoryCollection` inside `ConfigureAppConfiguration`\nto inject test-specific values — it is the last provider added and therefore wins.\nKeep test config minimal: only override values that differ from defaults or would\ncause the test to contact real external services.\n",{"id":82,"difficulty":58,"q":83,"a":84},"change-token","What is `IChangeToken` and how does it relate to configuration reload notifications?","**`IChangeToken`** is the low-level primitive that the configuration system uses to\nsignal when a source has changed. `IConfiguration.GetReloadToken()` returns a change\ntoken that fires once when any provider triggers a reload. You can use it to react\nto config changes in code that does not have access to `IOptionsMonitor\u003CT>`.\n\n```csharp\n\u002F\u002F Low-level change-token subscription:\nvoid WatchForChanges(IConfiguration config)\n{\n    \u002F\u002F GetReloadToken returns a one-shot token — must re-register after each fire:\n    ChangeToken.OnChange(\n        changeTokenProducer: () => config.GetReloadToken(),\n        changeTokenConsumer: () =>\n        {\n            Console.WriteLine(\"Configuration reloaded at \" + DateTime.UtcNow);\n            \u002F\u002F Re-read any cached config values here\n        });\n}\n\n\u002F\u002F IOptionsMonitor\u003CT> uses the same mechanism internally — prefer it for options:\npublic class FeatureFlagCache\n{\n    private HashSet\u003Cstring> _enabledFlags;\n\n    public FeatureFlagCache(IOptionsMonitor\u003CFeatureOptions> monitor)\n    {\n        _enabledFlags = BuildCache(monitor.CurrentValue);\n\n        \u002F\u002F OnChange callback fires whenever config changes on disk:\n        monitor.OnChange(opts =>\n        {\n            _enabledFlags = BuildCache(opts); \u002F\u002F rebuild the local cache\n            Console.WriteLine(\"Feature flags reloaded\");\n        });\n    }\n\n    private static HashSet\u003Cstring> BuildCache(FeatureOptions opts)\n        => opts.EnabledFlags.ToHashSet(StringComparer.OrdinalIgnoreCase);\n\n    public bool IsEnabled(string flag) => _enabledFlags.Contains(flag);\n}\n\n\u002F\u002F Custom IChangeToken implementation (e.g., for a DB-backed config provider):\npublic class DbChangeToken : IChangeToken\n{\n    private readonly CancellationToken _token;\n    public DbChangeToken(CancellationToken token) => _token = token;\n\n    public bool HasChanged => _token.IsCancellationRequested;\n    public bool ActiveChangeCallbacks => true;\n\n    public IDisposable RegisterChangeCallback(Action\u003Cobject?> callback, object? state)\n        => _token.Register(callback, state);\n}\n```\n\n**Rule of thumb:** Use `IOptionsMonitor\u003CT>.OnChange` for most config-reload\nscenarios — it is the safe, high-level API. Drop down to `IChangeToken` directly\nonly when building a custom configuration provider or when you need to watch for\nchanges outside the Options pattern.\n",15,null,{"description":11},"ASP.NET Core configuration interview questions — IConfiguration, IOptions, IOptionsMonitor, environment variables, user secrets, and startup validation.","dotnet\u002Faspnet-core\u002Fconfiguration","ASP.NET Core","aspnet-core","2026-06-23","U6tyViKfpJg8lm-Lcl1ez7oNVWLpnBW8qjECMvBsdss",[95,99,102,106],{"subtopic":96,"path":97,"order":98},"Middleware","\u002Fdotnet\u002Faspnet-core\u002Fmiddleware",1,{"subtopic":100,"path":101,"order":12},"Routing","\u002Fdotnet\u002Faspnet-core\u002Frouting",{"subtopic":103,"path":104,"order":105},"Controllers & Actions","\u002Fdotnet\u002Faspnet-core\u002Fcontrollers-actions",3,{"subtopic":6,"path":21,"order":20},{"path":108,"title":109},"\u002Fblog\u002Fdotnet-aspnet-core-configuration","ASP.NET Core Configuration in Depth",1782244118449]