Zonit.Extensions.Configuration 10.0.0-preview.18

This is a prerelease version of Zonit.Extensions.Configuration.
dotnet add package Zonit.Extensions.Configuration --version 10.0.0-preview.18
                    
NuGet\Install-Package Zonit.Extensions.Configuration -Version 10.0.0-preview.18
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Zonit.Extensions.Configuration" Version="10.0.0-preview.18" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Zonit.Extensions.Configuration" Version="10.0.0-preview.18" />
                    
Directory.Packages.props
<PackageReference Include="Zonit.Extensions.Configuration" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Zonit.Extensions.Configuration --version 10.0.0-preview.18
                    
#r "nuget: Zonit.Extensions.Configuration, 10.0.0-preview.18"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Zonit.Extensions.Configuration@10.0.0-preview.18
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Zonit.Extensions.Configuration&version=10.0.0-preview.18&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Zonit.Extensions.Configuration&version=10.0.0-preview.18&prerelease
                    
Install as a Cake Tool

Zonit.Extensions.Configuration

One configuration file per concern, instead of one appsettings.json in which the Serilog section buries everything else. Host-agnostic: the entry point extends IHostApplicationBuilder, so web, worker and console hosts use the same call. Depends only on Microsoft.Extensions.Configuration.Json and Microsoft.Extensions.Hosting.Abstractions — both of which an ASP.NET Core host already has from the shared framework — and on no other Zonit package.

NuGet Downloads

dotnet add package Zonit.Extensions.Configuration

Setup

var builder = WebApplication.CreateBuilder(args);

builder.AddAppData();   // first line — Kestrel and logging read configuration during Build()

There is a second overload on IServiceCollection, for callers that never see the host builder:

builder.Services.AddAppData();

It works because the host registers its ConfigurationManager as the IConfiguration service and that type implements IConfigurationBuilder too, so the source list is reachable from the collection alone. Both overloads share one idempotency marker, and both must run before Build() — reaching the manager is not the same as beating Kestrel and the logging providers to it.

Using Zonit.Extensions.Website? Install this package too and put builder.AddAppData() above AddWebsite. AddWebsite deliberately does not call it: o.AddArea<T>() runs each area's ConfigureServices during AddWebsite, and areas read configuration there, so a call from inside would always be too late for them.

var builder = WebApplication.CreateBuilder(args);

builder.AddAppData();
builder.Services.AddWebsite(o => o.AddArea<ShopArea>());

Get it backwards and an area fails at startup — loudly, not silently:

Zonit.Extensions.Databases.DatabaseException: Database configuration section not found.
   at SomeArea.ConfigureServices(...)
   at WebsiteOptions.AddArea[TArea]()

Layout

AppData/Settings/
  database.json            connection string
  kestrel.json             endpoints and certificate
  cultures.json            default culture and the supported list
  serilog.json             sinks and filters
  tenants.json             site identity: name, description, brand colours

  kestrel.dev.json         Development only — reserved ".dev.json" suffix
  database.local.json      machine-local secrets, gitignored

  Staging/                 folder name = ASPNETCORE_ENVIRONMENT
    kestrel.json

Each file is a normal configuration document — the section names are the same ones you would write in appsettings.json:

{
  "Culture": {
    "DefaultCulture": "pl-pl",
    "SupportedCultures": [ "en-us", "pl-pl" ]
  }
}

Files are merged, not chosen: database.json and kestrel.json both contribute, so keep one topic per file. Two files claiming the same section makes the winner depend on their names.

Load order

Later wins:

# Source
1 appsettings.json
2 appsettings.{Environment}.json
3 AppData/Settings/*.json — alphabetical
4 AppData/Settings/*.dev.json — Development only
5 AppData/Settings/*.local.json
6 AppData/Settings/{Environment}/… — same three groups again
7 user secrets
8 environment variables
9 command line

The files are inserted directly after the last appsettings*.json source, not appended. Appending would place them above the environment variables — which is how a container and a CI pipeline configure the app — and silently win over them. Hosts with no appsettings.json at all work the same way; the anchor then falls back to the front of the list.

Two ways to vary by environment

.dev.json is a reserved suffix meaning "Development only". It is short and unambiguous precisely because it is a fixed word. A general file.{Environment}.json convention could not be read reliably — market-data.api.json and market-data.Staging.json have the same shape, so the loader would have to guess whether the middle segment names an environment or part of the topic.

Every other environment therefore uses a folder, where no guessing is possible. If you need a literal "dev" in a topic name, write foo-dev.json.

Secrets

*.local.json loads last within its directory and is meant to sit in .gitignore: put a key in database.local.json next to database.json and it never reaches the repository.

Two things this does not do for you:

  • Exclude the pattern from the build output. .gitignore keeps a secret out of source control, not out of a container image. Add an explicit exclusion if AppData/** is copied to output.
  • Replace a vault. Production secrets belong in environment variables or a secret store, both of which override these files anyway.

Reload

Sources are registered with reloadOnChange: true, so editing a file applies in the running process — that is the switch that makes IOptionsMonitor<T> consumers, such as Zonit.Extensions.Cultures, actually see the change. Turn it off with o.ReloadOnChange = false where file watching is unreliable or costly (network-mounted volumes, some container filesystems); DOTNET_USE_POLLING_FILE_WATCHER=1 is usually a better answer than giving up reload entirely.

Options

Member Default Behaviour
SettingsPath "AppData/Settings" Relative to the content root. A path resolving outside it throws at startup rather than loading nothing quietly.
ReloadOnChange true Whether editing a file reloads configuration in the running process.
CreateIfMissing true Creates the directory in Development only, best-effort. An empty directory changes nothing at runtime, so a read-only content root in production is not worth failing a start over — IOException and UnauthorizedAccessException are swallowed.

Notes

  • Call before Build(). Kestrel and the logging providers read configuration while the host is being built.
  • A missing settings directory is a valid state — the host runs on whatever other sources it has.
  • Idempotent. Repeat calls are ignored, so a host may call AddAppData() explicitly even when something else already did. The first call's options are the ones that apply.
  • Trim- and AOT-safe: no reflection, no dynamic code. Binding your own options still goes through the configuration binding source generator as usual.

License

MIT.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
10.0.0-preview.18 0 8/9/2026
10.0.0-preview.17 26 8/9/2026
10.0.0-preview.16 27 8/9/2026
10.0.0-preview.15 35 8/7/2026
10.0.0-preview.14 41 8/6/2026