Configuration
The Configuration topic covers two packages that together provide layered, EditorConfig-style configuration for .NET applications. Bodu.Text.Configuration reads a single text file in the familiar INI / EditorConfig shape - preamble, glob-anchored sections, key = value properties - and projects it into a flattened, target-aware view of colon-delimited configuration keys. Bodu.Extensions.Configuration.Text bridges that view into the Microsoft.Extensions.Configuration world: an IConfigurationBuilder source alongside JSON and environment variables, IOptions<T> binding, and reload-on-change.
The split is deliberate. The parser, resolver, and typed view carry no dependency on Microsoft.Extensions.Configuration, so console tools, analyzers, and build tasks can consume configuration documents directly. The bridge is a thin host that any Microsoft.Extensions-based application adds on top - its overload set mirrors AddJsonFile / AddJsonStream, so call sites stay familiar.
A configuration file in this model is not a snapshot of a single object graph - it is a layered description of how properties change as a target path moves through a directory tree. The libraries' job is to collapse those layers down to the right answer for a specific target.
The pipeline
Configuration flows through five stages; every stage past the parse is opt-in.
| Stage | Performed by | Produces |
|---|---|---|
| Document model | The library's own trivia-preserving INI model | A ConfigurationDocument over the IniDocumentBase model - sections, entries, comments, ordering preserved; entries stay editable through IniSection. |
| Profile-validated parse | ConfigurationDocument with ConfigurationParseOptions | A ConfigurationDocument, optionally paired with diagnostics via ParseWithDiagnostics. |
| Layered resolution | Resolve(targetPath) with ConfigurationResolveOptions |
A ConfigurationView - preamble plus matching glob-anchored sections, layered last-wins. |
| Typed access | The view's getter family | GetString, GetInt32, GetBoolean, GetEnum<T>, and GetValue<T> for any ISpanParsable<T>. |
| Microsoft.Extensions bridge (optional) | TextConfigurationSource / TextConfigurationProvider | Colon-delimited keys in IConfiguration, section binding to IOptions<T>, reload tokens. |
Parse without resolving when you only want the document; resolve without typed accessors when you only need raw strings; skip the bridge entirely when you do not host in Microsoft.Extensions.
Behaviour at each stage is governed by a profile - a named, validated combination of parse, resolve, and write options. Four ship in the box: Bodu (the permissive default), EditorConfigCompatible (strict alignment with EditorConfig 0.17.2), Strict (deterministic parsing for generated files), and Relaxed (collect diagnostics from user-authored files instead of throwing). See Configuration concepts for one-line definitions of each.
One file, end to end
The same source text serves both packages. A file in the EditorConfig shape:
# Preamble - properties that apply before any section opens.
root = true
service.name = Bodu.Sample
# A section header is a glob pattern matched against the target path.
[*.cs]
format.indent.style = space
format.indent.size = 4
# Later sections override earlier sections for any path both match.
[src/**/*.cs]
format.indent.size = 2
logging.level.default = Warning
Reading it directly with Bodu.Text.Configuration:
using Bodu.Text.Configuration;
ConfigurationDocument document = ConfigurationDocument.Load(".boduconfig");
ConfigurationView view = document.Resolve("src/MyApp/Program.cs");
int indent = view.GetInt32("format:indent:size"); // 2 - the src/** section won
string level = view.GetString("logging:level:default"); // "Warning"
Or surfacing it through Microsoft.Extensions.Configuration with the bridge:
using Bodu.Extensions.Configuration.Text;
using Microsoft.Extensions.Configuration;
IConfiguration configuration = new ConfigurationBuilder()
.AddTextConfigurationFile(".boduconfig", targetPath: "src/MyApp/Program.cs")
.Build();
string? level = configuration["logging:level:default"]; // "Warning"
Dotted keys (logging.level.default) project to the canonical colon-delimited form (logging:level:default) under the default DotToColon key mapping, which is exactly the shape IConfiguration consumes - the bridge adds no translation layer of its own.
The packages
| Package | Status | What it provides | Docs |
|---|---|---|---|
Bodu.Text.Configuration |
Stable | The parser, profiles, layered resolver, typed ConfigurationView, key model, diagnostics, and round-trip Save. Built on its own trivia-preserving INI document model; no format-library or Microsoft.Extensions dependency. |
Intro · Concepts · Get started |
Bodu.Extensions.Configuration.Text |
Stable | The Microsoft.Extensions.Configuration bridge: AddTextConfigurationFile / AddTextConfigurationStream, the conventional .boduconfig → bodu.config probe, reload-on-change, and AddConfigurationOptions<T> binding. |
Intro · Concepts · Get started |
Boundaries
- Use
Bodu.Text.Iniinstead when you just need to read or edit an INI file with no layering, no profiles, and no glob resolution - its comment-preserving mutable DOM andIniSerializercover plain INI end to end.ConfigurationDocumentkeeps its own IniDocumentBase model, so the two libraries are independent; promote to the configuration layer when you need its resolution semantics. Note the name collision:Bodu.Text.Configuration.IniDocumentis this library's mutable, trivia-preserving document, whereasBodu.Text.Ini.Document.IniDocumentis the line-format package's read-only DOM - the two are unrelated types. - Skip the bridge when you don't host in
Microsoft.Extensions.Bodu.Text.Configurationis self-sufficient -Parse,Resolve, and the typed getters cover the full read path without anIConfigurationBuilderin sight. - The bridge is not a general INI provider. It exists specifically to surface profile-parsed, target-resolved Bodu configuration documents; for plain key-value INI in
IConfiguration, the stockMicrosoft.Extensions.Configuration.Iniprovider may be all you need.
Choosing an entry point
| Scenario | Reach for | Notes |
|---|---|---|
| Parse a configuration file and read typed values | ConfigurationDocument.Parse(text) → doc.Resolve(targetPath) → view.GetInt32(...) |
The minimal happy path; defaults to the Bodu profile. |
| Resolve per-file settings the EditorConfig way | doc.Resolve("src/Foo.cs") with ConfigurationParseOptions.EditorConfigCompatible |
Section headers are glob patterns matched against the target path; later matches win. |
| Surface every problem in a user-authored file at once | ConfigurationDocument.ParseWithDiagnostics(text, ConfigurationParseOptions.Relaxed) |
Diagnostics collect instead of throwing; the valid portions of the document remain usable. |
| Reject any input the parser cannot prove canonical | ConfigurationParseOptions.Strict |
Duplicate keys are disallowed; suited to generated files. |
| Round-trip a document through save | ConfigurationDocument.Save(doc, path) |
Comments, section ordering, and property ordering are preserved. |
| Feed the file into ASP.NET Core / Generic Host configuration | builder.AddTextConfigurationFile(".boduconfig") |
Keys surface in the colon-delimited form IConfiguration consumes. |
Bind a section to a POCO with IOptions<T> |
services.AddConfigurationOptions<MyOptions>(configuration, "section") |
A discoverability shim over the standard Configure<T> shape. |
| Hot-reload settings when the file changes | AddTextConfigurationFile(..., reloadOnChange: true) |
File watcher + standard reload tokens; IOptionsMonitor<T> re-binds automatically. |
| Test fixtures or embedded resources | builder.AddTextConfigurationStream(stream) |
One-shot; no reload-on-change. |
| Plain INI editing with no layering | Bodu.Text.Ini - the mutable, comment-preserving IniNode DOM (its IniDocument is the read-only DOM) |
The configuration layer is unnecessary overhead for that case. |
Install
dotnet add package Bodu.Text.Configuration
dotnet add package Bodu.Extensions.Configuration.Text
Bodu.Extensions.Configuration.Text depends on Bodu.Text.Configuration, so applications that host in Microsoft.Extensions need only the second command.
Where to go next
- Configuration concepts - the cross-package vocabulary: profiles, preamble, glob-anchored sections, layered resolution, views, sources, providers, reload tokens.
- Bodu.Text.Configuration introduction - the parser, resolver, and view model in detail.
- Bodu.Text.Configuration getting started - install + minimal samples for parse-resolve-read, profile presets, diagnostics, round-trip save.
- Bodu.Extensions.Configuration.Text introduction - the
IConfigurationBuilderintegration. - Bodu.Extensions.Configuration.Text getting started - install + minimal samples for the file overload, the stream overload, the conventional probe, and options binding.
- Configuration guides - recipe-style walk-throughs across both packages.
- API reference: Bodu.Text.Configuration · Bodu.Extensions.Configuration.Text