Configuration

Every app we build requires configuration settings in order to work. Secrets must never be checked in to a repository

Most apps we build are initialised from the WebApplication.CreateBuilder method. This initialises the following 6 configuration options from highest to lowest priority:

  1. Command-line arguments using the Command-line configuration provider. (Highest priority)
  2. Non-prefixed environment variables using the Non-prefixed environment variables configuration provider.
  3. User secrets when the app runs in the Development environment.
  4. appsettings.{Environment}.json using the JSON configuration provider. For example, appsettings.Production.json and appsettings.Development.json.
  5. appsettings.json using the JSON configuration provider.
  6. A fallback to the host configuration. (Lowest priority)

Configuration hierarchy

Our approach to configuration is:

  • Define all the keys and a value placeholder which the application will use in appsettings.json (this file is checked into source control so it should not contain any secrets or private information).
  • Local development settings are then placed in appsettings.Development.json - this file should not be checked in to source control as some of the settings might be specific to your development environment, secrets should not be in this file.
  • Local secrets are placed in your local UserSecrets
  • In production, configuration settings will be in an Azure AppConfiguration, secrets will be in a Key Vault.

As appsettings.json is checked in to source control, When the value will contain a secret then simply put SEE USER SECRETS OR KEY VAULT as the value of the key.

Local development should not be dependent on Azure AppConfiguration or Azure Key Vault. Secrets used for pre-production environments should not be the same as the production values.

Production configuration

Secrets must be in a Key Vault, configuration of the app should use Azure AppConfiguration (free version is likely to be sufficient for most clients).

This requires two nuget packages to be added to your API/Web:

dotnet add package Azure.Identity
dotnet add package Microsoft.Extensions.Configuration.AzureAppConfiguration
var builder = WebApplication.CreateBuilder(args);

// Implementing AzureAppConfiguration, with KeyVault access, using managed identities.
if (!builder.Environment.IsDevelopment){
    string appConfigEndpoint = builder.Configuration.GetValue<string>("AZURE_APPCONFIGURATION_ENDPOINT") 
        ?? throw new EnvironmentVariableNotFoundException("AZURE_APPCONFIGURATION_ENDPOINT");
    builder.Configuration.AddAzureAppConfiguration(options =>
        {
            options.Connect(
                new Uri(appConfigEndpoint),
                new ManagedIdentityCredential()
            );
            options.ConfigureKeyVault(keyVaultOptions =>
            {
                keyVaultOptions.SetCredential(new DefaultAzureCredential());
            });
        });
}

These Microsoft articles have more detailed information:

Mocking configuration

When you need to mock configuration you can use the InMemoryCollection.

Example appsettings file:

{
    "TopLevelKey": "TopLevelValue",
    "SectionName": {
        "SomeKey": "SectionValue"
    }
}

This can be mocked as follows:

var inMemorySettings = new Dictionary<string, string> {
    {"TopLevelKey", "TopLevelValue"},
    {"SectionName:SomeKey", "SectionValue"},
};

IConfiguration configuration = new ConfigurationBuilder()
    .AddInMemoryCollection(inMemorySettings)
    .Build();

See Mocking your appsettings in unit test on .NET article on Medium for more information.