Configuration in .NET

Modern .NET applications often require flexible, environment-aware configurations. .NET’s built-in configuration system, powered by IConfiguration, allows you to easily manage settings from multiple sources, including JSON files, environment variables, and more.

IConfiguration Overview

The IConfiguration interface in .NET provides a way to access key-value pairs from various configuration providers. It's commonly used to retrieve settings like connection strings, feature flags, and other application settings.

Configuration Providers

.NET's configuration system supports multiple providers. Here are a few common ones:

  • appsettings.json: The most common provider. It's a JSON file where you can define your configuration settings.
  • Environment Variables: Useful for injecting environment-specific settings, like in production environments.
  • User Secrets: Ideal for local development where sensitive information (like API keys) needs to be kept outside of source control.

Using IConfiguration

IConfiguration can be injected into classes, allowing you to access configurations from any source.

public class MyService
{
    private readonly IConfiguration _configuration;

    public MyService(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public void PrintSetting()
    {
        var setting = _configuration["MySetting"];
        Console.WriteLine(setting);
    }
}

This value could come from the appsettings.json file, environment variables, or command-line arguments.

Example appsettings.json file:

{
  "MySetting": "Hello, World!"
}

appsettings.json

The appsettings.json file is a standard way to manage configuration in .NET Core applications. The file uses a key-value structure to organize settings. You can also have environment-specific appsettings files, like appsettings.Development.json or appsettings.Production.json.

Example appsettings.json file:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning"
    }
  },
  "ConnectionStrings": {
    "DefaultConnection": "Server=myServer;Database=myDB;User Id=myUser;Password=myPass;"
  }
}

You can access the values in the appsettings.json file by referencing their key paths. Note the use of : to access the nested values.

var connectionString = _configuration["ConnectionStrings:DefaultConnection"];
Console.WriteLine(connectionString);

Connection strings are extremely common, so it has a special helper method to make it easier:

var connectionString = _configuration.GetConnectionString("DefaultConnection");
Console.WriteLine(connectionString);

Environment Variables

.NET's configuration system allows you to override values from appsettings.json using environment variables, which is helpful when deploying applications across multiple environments.

To set an environment variable in a terminal window:

export ConnectionStrings__DefaultConnection="Server=prodServer;Database=prodDB;User Id=prodUser;Password=prodPass;"

Bind Complex Objects

You can bind sections of the configuration directly to strongly typed objects, simplifying access to complex configurations.

public class AppSettings
{
    public string AppName { get; set; }
    public string BaseUrl { get; set; }
}

Then, bind the configuration to the object:

var appSettings = new AppSettings();
_configuration.GetSection("AppSettings").Bind(appSettings);

You can also use the Get<T> method to bind the configuration to a strongly typed object:

var appSettings = _configuration.GetSection("AppSettings").Get<AppSettings>();

Configuration in ASP.NET Core

In ASP.NET Core applications, the configuration system is integrated into the Generic Host. By default, appsettings.json, environment variables, and command-line arguments are all supported without additional setup.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                  .AddEnvironmentVariables()
                  .AddCommandLine(args);
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

Because it's important to understand what .NET considers "default", you should browse source code for the CreateDefaultBuilder method early and often to see how Microsoft "does things". You'd be surprised the number of times how I've been bitten by subtle behavior changes between default builders as the version of .NET has changed.