Table of Contents

Configuration

Arc4u builds on the .NET configuration system (IConfiguration and the options pattern) and adds three things: a small set of application-wide settings that other Arc4u packages read, a way to keep encrypted secrets in configuration files, and a database-backed configuration provider that reloads while the application runs. This guide is for the developer who wires an application's configuration. Arc4u registers these services through dependency injection.

What it solves

  • Application identity. Logging, caching and authorization need to know the application name, the environment and the time zone. Arc4u reads them once from the Application.Configuration section into ApplicationConfig.
  • Secrets in the repository. .NET user secrets stay on one machine. The decryptor lets you commit values encrypted with a certificate and decrypts them when the application starts.
  • Settings that change without a redeployment. The configuration store persists chosen sections in a database and reloads them in running instances.

Arc4u leaves the configuration sources (JSON files, environment variables, Azure App Configuration, and so on) to .NET: everything here is an IConfigurationProvider or a helper that reads IConfiguration.

flowchart LR
    Files["appsettings.json<br/>environment variables"] --> Root["IConfiguration"]
    Dec["Arc4u.Configuration.Decryptor<br/>decrypts Decrypt: values"] --> Root
    Store["Arc4u.Configuration.Store<br/>database sections"] --> Root
    Root --> Opt["Options: ApplicationConfig,<br/>your options types"]

Packages involved

Package Use it for
Arc4u.Configuration ApplicationConfig, AppSettings, ConfigureSettings and other helpers. Also a dependency of the Arc4u package.
Arc4u.Configuration.Decryptor Decrypt configuration values with a certificate or an AES key. See Decrypting secrets.
Arc4u.Configuration.Store A configuration provider that persists sections through ISectionStore and polls for changes.
Arc4u.Configuration.Store.EfCore The ISectionStore implementation for EF Core. See Configuration store.

Install

dotnet add package Arc4u.Configuration --prerelease
dotnet add package Arc4u.Configuration.Decryptor --prerelease
dotnet add package Arc4u.Configuration.Store.EfCore --prerelease

Install only the packages you use. Arc4u.Configuration.Decryptor depends on Arc4u, and Arc4u.Configuration.Store.EfCore depends on Arc4u.Configuration.Store.

Configuration

Section names follow the .NET rules: : separates levels, and the names of Arc4u sections are PascalCase words that can contain a dot, which is part of the key (Application.Configuration is one key at the root, not a section Application with a child Configuration). Each Arc4u feature documents the section it reads and the method parameter that renames it.

Application.Configuration

AddApplicationConfig(IConfiguration, string sectionName = "Application.Configuration") reads the section into ApplicationConfig and registers it as options.

{
  "Application.Configuration": {
    "ApplicationName": "Orders",
    "Environment": {
      "Name": "Dev",
      "LoggingName": "ORDERS-DEV",
      "TimeZone": "Romance Standard Time"
    }
  }
}
Key Type Default Description
Application.Configuration:ApplicationName string none (required) Name that identifies the application outside the logs, for example to the cache and authorization features.
Application.Configuration:Environment:Name string none (required) Name of the environment, for example Dev or Prod.
Application.Configuration:Environment:LoggingName string none (required) The value written in the Application property of every log entry.
Application.Configuration:Environment:TimeZone string none (required) A system time zone ID accepted by TimeZoneInfo.FindSystemTimeZoneById, used by TimeZoneContext. Examples: Romance Standard Time, Europe/Brussels.

The four values are required: a missing or empty value throws a ConfigurationException that lists all of them.

Code

// Program.cs
using Arc4u.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddApplicationConfig(builder.Configuration);
// builder.Services.AddApplicationConfig(builder.Configuration, "MyApp");   // another section name

var app = builder.Build();
app.Run();

Inject IOptions<ApplicationConfig> or IOptionsMonitor<ApplicationConfig> to read it. There is also an overload that takes an Action<ApplicationConfig>, for values that do not come from configuration.

Common scenarios

Read a group of string settings by name

ConfigureSettings reads a section as a dictionary of strings and registers it as a named SimpleKeyValueSettings option. Use it when several services each have a section with the same shape: one name per service.

{
  "Backends": {
    "Orders": {
      "Url": "https://orders.example.com",
      "Audience": "orders-api"
    }
  }
}
// Program.cs
using Arc4u.Configuration;

var builder = WebApplication.CreateBuilder(args);

var orders = builder.Services.ConfigureSettings("Orders", builder.Configuration, "Backends:Orders");
// orders.Values["Url"] == "https://orders.example.com"

var app = builder.Build();
app.Run();
// OrdersClient.cs
using Arc4u.Configuration;
using Microsoft.Extensions.Options;

public class OrdersClient(IOptionsMonitor<SimpleKeyValueSettings> settings)
{
    public string Url => settings.Get("Orders").Values["Url"];
}

IKeyValueSettings exposes the dictionary as Values. Only direct children of the section that have a string value are meaningful: it does not read nested sections. The method throws a ConfigurationException when the section does not exist.

Read the AppSettings section

AppSettings implements IAppSettings (also an IKeyValueSettings) and exposes the children of the AppSettings section as a read-only dictionary. It is marked for registration by the Arc4u dependency attributes; to register it yourself:

// Program.cs
using Arc4u;
using Arc4u.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<IAppSettings, AppSettings>();

var app = builder.Build();
app.Run();
{
  "AppSettings": {
    "Region": "eu"
  }
}

The dictionary is read once, when AppSettings is constructed. A missing AppSettings section gives an empty dictionary.

Keep secrets out of the repository

Use the decryptor: commit Decrypt:-prefixed values and provide the certificate at runtime.

Change settings without a redeployment

Use the configuration store: persist chosen sections in a database and let the running instances reload them.

Extensibility points

Everything here builds on standard .NET extension points. The Arc4u-specific ones are documented in the sub-pages:

Service Default implementation Replace it to
IX509CertificateLoader X509CertificateLoader Find the decryption certificate elsewhere. See Decrypting secrets.
ISectionStore EF Core store Persist sections somewhere other than a DbContext. See Configuration store.

Troubleshooting

No section with name ... exists

ConfigureSettings throws a ConfigurationException when the section is missing. Check the section path (: between levels) and that the provider holding it is registered.

The section 'Application.Configuration' does not exist or is empty

AddApplicationConfig(IConfiguration) throws a ConfigurationException with this text when the section has no values at all: the section is missing, or misspelled. Check the spelling of the section name and that the file that holds it is loaded.

Application name is not defined

The ConfigurationException message starts with "Application name is not defined in the initialization of the application config settings" and lists every required value of Application.Configuration that is empty.

See also