Tutorials ASP.NET Core Web API
App Settings & The Options Pattern
On this page
App Settings & The Options Pattern
Enterprise applications require configurable environments. The port your API runs on, the Database it connects to, and the API keys it uses for external services (like Stripe or AWS) must change autonomously depending on whether the app is running on your Local Laptop or the Production Server. The Options Pattern is how ASP.NET Core securely orchestrates these variables.
1. The appsettings.json Hierarchy
ASP.NET Core automatically loads configuration data in a cascading hierarchy. Variables defined in higher levels overwrite those in lower levels effortlessly.
appsettings.json(Base global settings)appsettings.Development.json(Overwrites base when running locally)- OS Environment Variables (Overwrites JSON; used heavily in Docker/Azure)
- Command Line Arguments (Absolute highest priority)
Example JSON Structure
{
"Logging": {
"LogLevel": { "Default": "Information" }
},
"PaymentGateway": {
"StripeApiKey": "sk_test_12345",
"MaxRetryAttempts": 3
}
}
2. The Anti-Pattern: IConfiguration Injection
You can technically inject the raw IConfiguration interface into any controller and read the JSON via magic strings. Do not do this.
❌ Magic Strings are brittle
public class PaymentController {
private readonly IConfiguration _config;
// ...
public void Process() {
// If someone renames the JSON key, this silently returns NULL at runtime and crashes!
var key = _config["PaymentGateway:StripeApiKey"];
}
}
3. The Solution: The Options Pattern (Strongly Typed Config)
Instead of strings, we map the JSON section directly to a strongly-typed C# class. This provides 100% Intellisense and compile-time safety.
Step 1: Create the POCO Class
public class PaymentOptions
{
// The property names must exactly match the JSON keys
public string StripeApiKey { get; set; }
public int MaxRetryAttempts { get; set; }
}
Step 2: Bind it in Program.cs
// This automatically parses the "PaymentGateway" JSON block into the PaymentOptions class
// and registers it globally in the Dependency Injection container.
builder.Services.Configure<PaymentOptions>(
builder.Configuration.GetSection("PaymentGateway")
);
Step 3: Inject IOptions<T> into the Controller
public class PaymentController : ControllerBase
{
private readonly PaymentOptions _paymentOptions;
// Use IOptions to extract the strongly typed class
public PaymentController(IOptions<PaymentOptions> options)
{
_paymentOptions = options.Value;
}
[HttpPost]
public IActionResult Charge()
{
// Beautiful, strongly-typed Intellisense. No magic strings!
var key = _paymentOptions.StripeApiKey;
return Ok();
}
}
4. Interview Mastery
Q: "Can you explain the difference between IOptions, IOptionsSnapshot, and IOptionsMonitor?"
Architect Answer: "They determine how the application reacts to configuration changes *while the server is running*. IOptions registers as a Singleton on startup. If you manually edit the 'appsettings.json' file on the server while the app is running, 'IOptions' will NEVER read the new changes until you physically restart IIS. IOptionsSnapshot fixes this; it registers as Scoped. It re-reads the JSON file at the beginning of every new HTTP Request, allowing you to hot-swap configuration values in production without downtime. IOptionsMonitor is also dynamic but used specifically for Singleton services."