Skip to content

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:

  1. Direct access using the built-in Configuration property
  2. Section binding to strongly-typed classes
  3. Dependency injection configuration for services

Accessing Configuration Directly ​

The simplest approach uses the Configuration property available on the WebApplicationBuilder:

csharp
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 ​

csharp
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 ​

csharp
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 ​

csharp
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 ​

csharp
// 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 ​

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 ​

csharp
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:

  1. Ensure appsettings.json is properly formatted with valid JSON
  2. Verify the file properties - "Copy to Output Directory" should be set to "Copy if newer"
  3. 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