Configuration & appsettings.json
đ¯ What You'll Learn
- Understanding ASP.NET Core configuration system
- Working with appsettings.json
- Environment-specific configuration files
- Configuration sources and precedence
- Reading configuration values
- Strongly-typed configuration with IConfiguration
- Connection strings and secrets management
- Best practices for InvenTrack configuration
The Configuration System
ASP.NET Core has a flexible, hierarchical configuration system that loads settings from multiple sources:
appsettings.jsonappsettings.{Environment}.json- User secrets (Development only)
- Environment variables
- Command-line arguments
Later sources override earlier ones. For example, environment variables override appsettings.json. This lets you have default settings in JSON files and override them in production with environment variables.
appsettings.json Structure
The default appsettings.json looks like this:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
InvenTrack Configuration Example
Here's a more complete configuration for InvenTrack:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=InvenTrack;Trusted_Connection=true;TrustServerCertificate=true"
},
"JwtSettings": {
"Secret": "your-secret-key-here-min-32-chars",
"Issuer": "InvenTrack.Api",
"Audience": "InvenTrack.Client",
"ExpirationMinutes": 60
},
"EmailSettings": {
"SmtpServer": "smtp.gmail.com",
"SmtpPort": 587,
"SenderEmail": "noreply@inventtrack.com",
"SenderName": "InvenTrack System",
"EnableSsl": true
},
"InventorySettings": {
"LowStockThreshold": 10,
"EnableAutoReorder": false,
"DefaultCurrency": "USD"
},
"CorsSettings": {
"AllowedOrigins": [
"http://localhost:3000",
"http://localhost:4200"
]
}
}
Don't put real passwords, API keys, or connection strings in appsettings.json
if you're committing to Git. Use User Secrets for development and environment variables
for production.
Environment-Specific Configuration
You can have different settings for different environments:
appsettings.json- Base settings (all environments)appsettings.Development.json- Development overridesappsettings.Production.json- Production overridesappsettings.Staging.json- Staging overrides
appsettings.Development.json
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft.AspNetCore": "Information"
}
},
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=InvenTrack_Dev;Trusted_Connection=true;TrustServerCertificate=true"
},
"EmailSettings": {
"SmtpServer": "localhost",
"SmtpPort": 25,
"EnableSsl": false
}
}
appsettings.Production.json
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft.AspNetCore": "Error"
}
},
// Connection string set via environment variable
"InventorySettings": {
"EnableAutoReorder": true
}
}
ASP.NET Core loads appsettings.json first, then loads
appsettings.{Environment}.json and merges/overrides values. The environment
is determined by the ASPNETCORE_ENVIRONMENT variable.
Reading Configuration Values
Method 1: Direct Access with IConfiguration
public class ProductsController : ControllerBase
{
private readonly IConfiguration _configuration;
public ProductsController(IConfiguration configuration)
{
_configuration = configuration;
}
[HttpGet("settings")]
public IActionResult GetSettings()
{
// Simple value
var allowedHosts = _configuration["AllowedHosts"];
// Nested value
var logLevel = _configuration["Logging:LogLevel:Default"];
// Connection string
var connString = _configuration.GetConnectionString("DefaultConnection");
// With default value
var threshold = _configuration.GetValue<int>("InventorySettings:LowStockThreshold", 5);
return Ok(new { allowedHosts, logLevel, threshold });
}
}
Configuration Path Syntax
| JSON Structure | Configuration Path |
|---|---|
{ "Key": "Value" } |
"Key" |
{ "Parent": { "Child": "Value" } } |
"Parent:Child" |
{ "Array": ["A", "B"] } |
"Array:0", "Array:1" |
Method 2: GetSection
// Get entire section
var jwtSection = _configuration.GetSection("JwtSettings");
// Read values from section
var secret = jwtSection["Secret"];
var issuer = jwtSection["Issuer"];
var expiration = jwtSection.GetValue<int>("ExpirationMinutes");
Method 3: Bind to Object
// Define a class
public class JwtSettings
{
public string Secret { get; set; } = string.Empty;
public string Issuer { get; set; } = string.Empty;
public string Audience { get; set; } = string.Empty;
public int ExpirationMinutes { get; set; }
}
// Bind configuration to object
var jwtSettings = new JwtSettings();
_configuration.GetSection("JwtSettings").Bind(jwtSettings);
// Or use Get<T> (creates new instance)
var jwtSettings2 = _configuration.GetSection("JwtSettings").Get<JwtSettings>();
Connection Strings
Connection strings have a special section and helper method:
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=InvenTrack;...",
"ReportingDb": "Server=localhost;Database=InvenTrack_Reports;..."
}
}
// In Program.cs
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<InvenTrackDbContext>(options =>
options.UseSqlServer(connectionString));
User Secrets (Development)
For development, use User Secrets to store sensitive data outside your project folder:
Initialize User Secrets
# Initialize user secrets for your project
dotnet user-secrets init
# Set a secret
dotnet user-secrets set "JwtSettings:Secret" "my-super-secret-key-min-32-chars"
# Set connection string
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Server=localhost;Database=InvenTrack;User Id=sa;Password=MyPassword123"
# List all secrets
dotnet user-secrets list
# Remove a secret
dotnet user-secrets remove "JwtSettings:Secret"
# Clear all secrets
dotnet user-secrets clear
User secrets are stored in:
Windows: %APPDATA%\Microsoft\UserSecrets\{id}\secrets.json
macOS/Linux: ~/.microsoft/usersecrets/{id}/secrets.json
They're not encrypted, just stored outside your project.
Environment Variables
In production, use environment variables for secrets:
Setting Environment Variables
# Set for current session
$env:ConnectionStrings__DefaultConnection = "Server=prod-server;..."
# Set permanently (system-wide)
[System.Environment]::SetEnvironmentVariable("ConnectionStrings__DefaultConnection", "Server=prod-server;...", "Machine")
# Set for current session
export ConnectionStrings__DefaultConnection="Server=prod-server;..."
# Add to ~/.bashrc or ~/.zshrc for persistence
echo 'export ConnectionStrings__DefaultConnection="Server=prod-server;..."' >> ~/.bashrc
Use double underscores (__) to represent hierarchy in environment
variables:
ConnectionStrings:DefaultConnection â
ConnectionStrings__DefaultConnection
JwtSettings:Secret â JwtSettings__Secret
Configuration in Program.cs
You can customize configuration sources:
var builder = WebApplication.CreateBuilder(args);
// Add custom configuration sources
builder.Configuration
.AddJsonFile("appsettings.Custom.json", optional: true)
.AddXmlFile("config.xml", optional: true)
.AddIniFile("config.ini", optional: true)
.AddEnvironmentVariables("INVENTTRACK_")
.AddCommandLine(args);
Best Practices
1. Never Commit Secrets
- Use User Secrets for development
- Use environment variables for production
- Add
appsettings.*.jsonto .gitignore if it contains secrets
2. Use Strongly-Typed Configuration
Instead of reading strings everywhere, use the Options pattern (covered in next section):
// Register options
builder.Services.Configure<JwtSettings>(
builder.Configuration.GetSection("JwtSettings"));
// Inject IOptions<JwtSettings> instead of IConfiguration
3. Organize Configuration Logically
{
// Framework settings
"Logging": { ... },
"AllowedHosts": "*",
// Infrastructure
"ConnectionStrings": { ... },
// Application settings (grouped by feature)
"JwtSettings": { ... },
"EmailSettings": { ... },
"InventorySettings": { ... }
}
4. Use Environment-Specific Files
appsettings.json- Shared defaultsappsettings.Development.json- Dev overrides (commit this)appsettings.Production.json- Prod overrides (minimal, no secrets)
5. Validate Configuration
// In Program.cs, after building
var jwtSecret = builder.Configuration["JwtSettings:Secret"];
if (string.IsNullOrEmpty(jwtSecret) || jwtSecret.Length < 32)
{
throw new InvalidOperationException("JWT Secret must be at least 32 characters");
}
Key Takeaways
- ASP.NET Core loads configuration from multiple sources
- Configuration precedence: JSON â User Secrets â Env Vars â Command Line
appsettings.jsoncontains base settingsappsettings.{Environment}.jsonoverrides for specific environments- Access configuration via IConfiguration
- Use colon (:) for hierarchy:
"Parent:Child" - Use double underscore (__) in environment variables
- User Secrets for development (never commit secrets!)
- Environment variables for production
GetConnectionString()helper for connection stringsBind()orGet<T>()for strongly-typed configuration- Validate critical configuration at startup
You now understand how to manage configuration in ASP.NET Core! In the next section, we'll explore the Options Patternâa better way to work with configuration using strongly-typed classes, validation, and dependency injection.