Modern applications need flexible, secure, and environment-aware configuration systems. ASP.NET Core provides one of the most powerful and extensible configuration frameworks in any web platform today. The modern configuration system is designed to work across environments, support multiple formats, enable strong typing, and integrate seamlessly with cloud platforms and secret management services.
Unlike the older .NET Framework approach that mainly relied on a single web.config file, ASP.NET Core's configuration system is built on a provider-based model. This allows configuration values to come from many different sources such as JSON files, environment variables, command-line arguments, secret stores, and cloud configuration services.
![ModernConfiguration]()
Why a Modern Configuration System?
Earlier systems had limitations:
ASP.NET Core solves these through:
Multiple configuration providers
Hierarchical key-value structure
Environment-based configuration
Dependency injection support
Strongly typed settings
Secure secret management
Configuration Providers (Sources)
ASP.NET Core reads configuration from many providers in a specific order of priority:
appsettings.json
appsettings.{Environment}.json
User Secrets (Development only)
Environment Variables
Command-line Arguments
Later providers override earlier ones.
appsettings.json Example
{"Application": {
"Name": "DemoApp",
"Version": "2.1"},"Database": {
"ConnectionString": "Server=.;Database=DemoDB;Trusted_Connection=True;",
"Timeout": 30},"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning"
}}}
Reading Configuration Values
Basic Example
var builder = WebApplication.CreateBuilder(args);
string appName = builder.Configuration["Application:Name"];
string connectionString = builder.Configuration["Database:ConnectionString"];
The colon (:) represents hierarchy inside JSON.
Environment-Specific Configuration
Create files:
Example
{"Database": {
"ConnectionString": "Server=DEV;Database=TestDB"}}
ASP.NET Core automatically loads the correct configuration based on:
ASPNETCORE_ENVIRONMENT=Development
Strongly Typed Configuration (Options Pattern)
Instead of accessing configuration with strings, map settings to C# classes.
Step 1: Create a settings class
public class DatabaseSettings
{
public string ConnectionString { get; set; }
public int Timeout { get; set; }
}
Step 2: Bind configuration
builder.Services.Configure<DatabaseSettings>(
builder.Configuration.GetSection("Database"));
Step 3: Inject into services/controllers
public class DataService
{
private readonly DatabaseSettings _settings;
public DataService(IOptions<DatabaseSettings> options)
{
_settings = options.Value;
}
}
Multiple Configuration Files
Load additional configuration files:
builder.Configuration
.AddJsonFile("features.json", optional: true)
.AddJsonFile("pricing.json", optional: true);
Enables module-based configuration management.
Environment Variables
Environment variables override json values.
Example
Set:
Database__Timeout=60
Double underscores (__) map to JSON sections.
Read it like:
var timeout = builder.Configuration["Database:Timeout"];
Command Line Configuration
dotnet run --Database:Timeout=100
This overrides everything.
User Secrets (for Development)
Avoid storing passwords in code:
dotnet user-secrets init
dotnet user-secrets set "Database:ConnectionString" "SecureValue"
Read it same as configuration:
builder.Configuration["Database:ConnectionString"];
Secrets never get committed.
Secure Secrets in Production
In production, integrate secret managers:
Azure Key Vault
AWS Secrets Manager
HashiCorp Vault
Example (Azure Key Vault):
builder.Configuration.AddAzureKeyVault(
new Uri("https://myvault.vault.azure.net/"),
new DefaultAzureCredential());
Configuration Reloading
Reload on change:
builder.Configuration
.AddJsonFile("appsettings.json", optional:false, reloadOnChange:true);
File changes update configuration without restarting application.
Configuration in Minimal APIs
var app = builder.Build();
app.MapGet("/config", (IConfiguration config) =>
{
return config["Application:Name"];
});
Validation of Configuration
Prevent startup from failing silently:
builder.Services
.AddOptions<DatabaseSettings>()
.BindConfiguration("Database")
.ValidateDataAnnotations()
.Validate(s => s.Timeout > 10, "Timeout too short");
IOptions Variants
| Type | Purpose |
|---|
| IOptions | Singleton access |
| IOptionsSnapshot | Scoped per request |
| IOptionsMonitor | Live reloading |
Example:
public class MyService
{
public MyService(IOptionsMonitor<DatabaseSettings> options)
{
options.OnChange(updated =>
{
Console.WriteLine("Settings updated");
});
}
}
Using Configuration in Middleware
app.Use(async (context, next) =>
{
var mode = context.RequestServices.GetRequiredService<IConfiguration>()["Mode"];
if (mode == "Maintenance")
{
context.Response.StatusCode = 503;
return;
}
await next();
});
Best Practices
✅ Never store secrets in Git
✅ Use options pattern
✅ Separate configs by environment
✅ Use environment variables in containers
✅ Validate your config on startup
✅ Use secret managers
✅ Avoid magic strings
✅ Use reload where applicable
Real-World SaaS Practice
In SaaS:
Feature flags from config
Plan-based limits from config
API keys from vault
Email gateways from config
Tenant rules from config
Configuration becomes operational control, not just app settings.
Conclusion
ASP.NET Core’s modern configuration system is built for real-world applications that need flexibility, security, and scalability. From local development to enterprise cloud environments, it enables developers to manage settings without rewriting code or redeploying applications.
Whether you are building a simple API or a large SaaS application, mastering the configuration system ensures secure deployments, easier debugging, and smoother operations.