name: aspnet-configuration description: Guide for ASP.NET Core configuration with appsettings.json, environment-specific settings, and the options pattern type: domain enforcement: suggest priority: medium
ASP.NET Core Configuration
This skill provides guidance for configuration management in ASP.NET Core applications using appsettings.json, environment-specific settings, user secrets, and the options pattern.
Table of Contents
- Configuration Files
- Environment-Specific Configuration
- Accessing Configuration
- Options Pattern
- User Secrets
- Best Practices
- Quick Reference
Configuration Files
appsettings.json
Both projects have appsettings.json:
src/ClaudeStack.Web/appsettings.jsonsrc/ClaudeStack.API/appsettings.json
Standard structure:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Configuration Hierarchy
ASP.NET Core loads configuration in this order (later sources override earlier):
- appsettings.json
- appsettings.{Environment}.json
- User Secrets (Development only)
- Environment variables
- Command-line arguments
Environment-Specific Configuration
appsettings.Development.json
Overrides appsettings.json in Development environment:
src/ClaudeStack.Web/appsettings.Development.jsonsrc/ClaudeStack.API/appsettings.Development.json
Example:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Information"
}
}
}
Determining Environment
Set via environment variable:
# Windows
$env:ASPNETCORE_ENVIRONMENT="Development"
# Linux/macOS
export ASPNETCORE_ENVIRONMENT=Development
Check in code:
if (app.Environment.IsDevelopment())
{
app.MapOpenApi(); // Only in development
}
Creating Environment-Specific Files
# Create production settings
# src/ClaudeStack.Web/appsettings.Production.json
Automatically loaded when ASPNETCORE_ENVIRONMENT=Production.
Accessing Configuration
IConfiguration Interface
In Program.cs (Minimal API):
var builder = WebApplication.CreateBuilder(args);
// Access configuration from builder
var connectionString = builder.Configuration["ConnectionStrings:DefaultConnection"];
var app = builder.Build();
// Access configuration in endpoint
app.MapGet("/config", (IConfiguration config) =>
{
var value = config["MySettings:MyValue"];
return value;
});
In MVC Controller:
public class HomeController : Controller
{
private readonly IConfiguration _configuration;
public HomeController(IConfiguration configuration)
{
_configuration = configuration;
}
public IActionResult Index()
{
var value = _configuration["MySettings:MyValue"];
return View();
}
}
Nested Configuration
appsettings.json:
{
"Database": {
"ConnectionString": "Server=localhost;Database=MyDb",
"Timeout": 30
}
}
Access:
var connectionString = config["Database:ConnectionString"];
var timeout = config.GetValue<int>("Database:Timeout");
Options Pattern
Strongly-Typed Configuration
1. Define options class:
public class DatabaseOptions
{
public string ConnectionString { get; set; }
public int Timeout { get; set; }
}
2. Bind configuration:
// In Program.cs
builder.Services.Configure<DatabaseOptions>(
builder.Configuration.GetSection("Database"));
3. Use in services/controllers:
public class UserService
{
private readonly DatabaseOptions _options;
public UserService(IOptions<DatabaseOptions> options)
{
_options = options.Value;
}
public void Connect()
{
var conn = _options.ConnectionString;
}
}
IOptions vs IOptionsSnapshot vs IOptionsMonitor
IOptions<T> // Singleton, never reloads
IOptionsSnapshot<T> // Scoped, reloads per request
IOptionsMonitor<T> // Singleton, reloads on change
Use IOptions for most cases. Use IOptionsSnapshot if configuration changes between requests. Use IOptionsMonitor to react to configuration changes in real-time.
User Secrets
Overview
User Secrets stores sensitive configuration outside the project directory. Used in Development only.
For:
- API keys
- Connection strings
- Passwords
Not for:
- Production secrets (use Azure Key Vault, etc.)
- Non-sensitive settings
Initialize User Secrets
cd src/ClaudeStack.Web
dotnet user-secrets init
Adds <UserSecretsId> to .csproj:
<PropertyGroup>
<UserSecretsId>guid-here</UserSecretsId>
</PropertyGroup>
Set Secrets
# Set individual secret
dotnet user-secrets set "ApiKey" "secret-value-123"
# Set nested secret
dotnet user-secrets set "Database:ConnectionString" "Server=..."
# List all secrets
dotnet user-secrets list
# Remove secret
dotnet user-secrets remove "ApiKey"
# Clear all secrets
dotnet user-secrets clear
Access Secrets
Same as regular configuration:
var apiKey = builder.Configuration["ApiKey"];
Location:
- Windows:
%APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json - Linux/macOS:
~/.microsoft/usersecrets/<user_secrets_id>/secrets.json
Best Practices
1. Never Commit Secrets
# .gitignore already includes:
appsettings.Development.json # Sometimes
**/secrets.json
Use User Secrets for local development secrets.
2. Use Options Pattern
Prefer:
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MySettings"));
Over:
var value = builder.Configuration["MySettings:Value"]; // Weakly-typed
3. Validate Options
builder.Services.AddOptions<DatabaseOptions>()
.Bind(builder.Configuration.GetSection("Database"))
.ValidateDataAnnotations()
.ValidateOnStart();
public class DatabaseOptions
{
[Required]
public string ConnectionString { get; set; }
[Range(1, 300)]
public int Timeout { get; set; }
}
4. Environment-Specific Settings
// appsettings.json - defaults
{
"Database": {
"ConnectionString": "Server=localhost"
}
}
// appsettings.Production.json - production overrides
{
"Database": {
"ConnectionString": "Server=prod-server"
}
}
5. Connection Strings
Special section:
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=MyDb"
}
}
Access:
var connStr = builder.Configuration.GetConnectionString("DefaultConnection");
Quick Reference
Configuration Access
// Simple value
config["MyKey"]
// Nested value
config["Section:SubSection:Key"]
// Typed value
config.GetValue<int>("Section:IntKey")
// Connection string
config.GetConnectionString("DefaultConnection")
// Entire section
var section = config.GetSection("MySection")
Options Pattern
// Register
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MySection"));
// Use (constructor injection)
public MyService(IOptions<MyOptions> options)
{
var value = options.Value.Property;
}
User Secrets Commands
dotnet user-secrets init
dotnet user-secrets set "Key" "Value"
dotnet user-secrets list
dotnet user-secrets remove "Key"
dotnet user-secrets clear
Environment Setup
# Set environment
$env:ASPNETCORE_ENVIRONMENT="Development"
# Check in code
if (app.Environment.IsDevelopment()) { }
if (app.Environment.IsProduction()) { }
Related Skills
- dotnet-minimal-apis: Using configuration in minimal APIs
- dotnet-cli-essentials: Running applications with different environments
Additional Resources
Version Information
- ASP.NET Core: 10.0 RC 2
- .NET SDK: 10.0.100-rc.2.25502.107
Configuration system is stable across .NET versions. This project uses .NET 10 RC 2 patterns.