Using appsettings.json in ASP.NET Core 6+ Program.cs
Problem Statement
With the introduction of ASP.NET Core 6, Microsoft merged the Startup.cs
and Program.cs
files into a single streamlined Program.cs
file using top-level statements. This architectural change left many developers unsure how to properly access configuration settings from appsettings.json
and use dependency injection in the new minimal hosting model.
The core challenge is accessing configuration values and binding them to services during application startup without the traditional Startup
class structure.
Solution Overview
ASP.NET Core 6+ provides several approaches to access configuration values from appsettings.json
in the Program.cs
file:
- Direct access using the built-in
Configuration
property - Section binding to strongly-typed classes
- Dependency injection configuration for services
Accessing Configuration Directly
The simplest approach uses the Configuration
property available on the WebApplicationBuilder
:
var builder = WebApplication.CreateBuilder(args);
// Access individual values using colon-separated keys
var redisConfig = builder.Configuration["RedisCacheOptions:Configuration"];
var jwtKey = builder.Configuration["Jwt:Key"];
// Or use GetValue for type conversion
var testValue = builder.Configuration.GetValue<string>("TestValue");
var allowedOrigins = builder.Configuration.GetValue<string>("AllowedOrigins");
// For connection strings specifically
var connectionString = builder.Configuration.GetConnectionString("Default");
Binding Configuration Sections to Classes
For better maintainability and type safety, bind configuration sections to strongly-typed classes:
1. Define Configuration Classes
public class RedisCacheOptions
{
public string Configuration { get; set; }
}
public class JwtSettings
{
public string Key { get; set; }
public string Issuer { get; set; }
public string Audience { get; set; }
public TokenLifetime TokenLifetime { get; set; }
}
public class TokenLifetime
{
public TimeSpan Mobile { get; set; }
public TimeSpan Web { get; set; }
}
2. Bind and Use Configuration in Program.cs
var builder = WebApplication.CreateBuilder(args);
// Method 1: Manual binding
var redisOptions = new RedisCacheOptions();
builder.Configuration.GetSection("RedisCacheOptions").Bind(redisOptions);
// Method 2: Automatic binding with Get<T>()
var jwtSettings = builder.Configuration.GetSection("Jwt").Get<JwtSettings>();
// Use the configured values
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = redisOptions.Configuration;
});
Configuring Dependency Injection
For services that need configuration, use the Options pattern:
1. Register Configuration with DI Container
var builder = WebApplication.CreateBuilder(args);
// Register configuration sections for dependency injection
builder.Services.Configure<RedisCacheOptions>(
builder.Configuration.GetSection("RedisCacheOptions"));
builder.Services.Configure<JwtSettings>(
builder.Configuration.GetSection("Jwt"));
2. Inject Configuration in Services
// Service that uses configured options
public class MyService
{
private readonly JwtSettings _jwtSettings;
public MyService(IOptions<JwtSettings> jwtOptions)
{
_jwtSettings = jwtOptions.Value;
}
public string GetJwtKey() => _jwtSettings.Key;
}
Complete Practical Example
Here's a comprehensive example showing how to replace hardcoded values with configuration from appsettings.json
:
appsettings.json
{
"Redis": "localhost:6379",
"Jwt": {
"Key": "YourSecretKeyHere",
"Issuer": "yourdomain.com",
"Audience": "youraudience"
},
"AllowedOrigins": "https://localhost:3000;https://localhost:3001",
"ConnectionStrings": {
"Default": "Server=localhost;Database=MyDb;Trusted_Connection=true"
}
}
Program.cs Implementation
var builder = WebApplication.CreateBuilder(args);
// Access configuration values
var redisConnection = builder.Configuration["Redis"];
var allowedOrigins = builder.Configuration.GetValue<string>("AllowedOrigins");
// Configure services with retrieved values
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = redisConnection;
});
// Configure CORS using settings from appsettings.json
if (!string.IsNullOrEmpty(allowedOrigins))
{
builder.Services.AddCors(options =>
{
var origins = allowedOrigins.Split(";");
options.AddPolicy("CorsPolicy", policy =>
{
policy.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.WithOrigins(origins);
});
});
}
// Register strongly-typed configuration
builder.Services.Configure<JwtSettings>(builder.Configuration.GetSection("Jwt"));
var app = builder.Build();
// Use CORS middleware
app.UseCors("CorsPolicy");
// Remaining middleware configuration
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Best Practices and Considerations
TIP
- Use strongly-typed configurations whenever possible for better maintainability and type safety
- Leverage the Options pattern for services that need configuration values
- Validate configuration values at startup to catch missing or invalid settings early
WARNING
- Avoid hardcoding configuration keys throughout your application - centralize configuration access
- Be cautious with sensitive data - use User Secrets for development and secure storage for production
Troubleshooting Common Issues
If you encounter problems accessing configuration values:
- Ensure appsettings.json is properly formatted with valid JSON
- Verify the file properties - "Copy to Output Directory" should be set to "Copy if newer"
- Check environment-specific appsettings - values may be overridden by
appsettings.Development.json
Conclusion
The ASP.NET Core 6+ minimal hosting model provides straightforward access to configuration through the WebApplicationBuilder.Configuration
property. By using direct value access, section binding, or the Options pattern, you can effectively utilize appsettings.json
values throughout your application while maintaining clean, maintainable code.
The key is choosing the right approach for your scenario:
- Simple values: Use direct access with
builder.Configuration["Key"]
- Related settings: Use section binding with strongly-typed classes
- Service configuration: Use the Options pattern with dependency injection