Skip to content
github-actions[bot] edited this page Apr 13, 2026 · 9 revisions

Registry API Reference

IniConfigRegistry

IniConfigRegistry is a thread-safe global registry that maps INI file basenames to their loaded IniConfig instances.

The .ini extension is optional in every method that accepts a file name — "myapp" and "myapp.ini" resolve to the same registry entry.

Method Description
ForFile(fileName) Returns a fluent IniConfigBuilder for the given file. The .ini extension is stripped if present.
Get(fileName) Returns the IniConfig for the file; throws KeyNotFoundException if not registered
Get() Returns the single registered IniConfig. Throws InvalidOperationException when 0 or more than one config is registered — use Get(fileName) in that case.
TryGet(fileName, out config) Returns false if the file has not been registered
GetSection<T>(fileName) Shortcut for Get(fileName).GetSection<T>()
GetSection<T>() Shortcut for Get().GetSection<T>() — works only when exactly one config is registered
AddSection<T>(fileName, section) Registers a section on an existing config without I/O — for plugin pre-init. See Plugin-Registrations.
Unregister(fileName) Removes a registration (useful in tests)
Clear() Removes all registrations (useful in tests)

No-argument convenience overloads

When an application registers exactly one INI file (the common case), the file name can be omitted entirely:

// Startup
IniConfigRegistry.ForFile("appsettings")   // ".ini" is optional here too
    .AddSearchPath(AppContext.BaseDirectory)
    .RegisterSection<IAppSettings>(new AppSettingsImpl())
    .Build();

// Anywhere in the app — no need to pass the file name
var settings = IniConfigRegistry.GetSection<IAppSettings>();

If more than one INI file is registered, Get() / GetSection<T>() throw InvalidOperationException with a message that points to the named overload.


IniConfig

Member Description
GetSection<T>() Returns the registered section instance; throws if not found. Always returns the same object reference.
GetSection(sectionName) Returns the section whose SectionName matches (case-insensitive), or null if not registered. Useful for generic / dynamic access. See Generic-Access.
GetSections() Returns IEnumerable<IIniSection> over all registered sections. Enables generic iteration without compile-time type knowledge. See Generic-Access.
AddSection<T>(section) Registers a section without any file I/O. Returns section for chaining. For use between Create() and Load(). See Plugin-Registrations.
AddSection(section) Non-generic overload; infers the interface type at runtime. Prefer the generic overload (AOT/trim safe).
Load() Reads all files and applies value sources once for every registered section. Returns this.
LoadAsync(ct) Async variant of Load(); also applies IValueSourceAsync sources and calls IAfterLoadAsync hooks.
Save() Writes all section values to disk, honoring IBeforeSave/IAfterSave hooks
SaveAsync(ct) Async variant of Save(); prefers IBeforeSaveAsync/IAfterSaveAsync hooks, falls back to sync hooks
Reload() Re-reads all layers in place; section references remain valid
ReloadAsync(ct) Async variant of Reload(); also applies IValueSourceAsync sources and calls IAfterLoadAsync hooks
HasPendingChanges() Returns true when at least one registered section has unsaved changes
RequestPostponedReload() Triggers a reload that was earlier postponed by a FileChangedCallback
InitialLoadTask Task.CompletedTask after Build(); a pending Task after BuildAsync() that completes when loading finishes
Metadata The IniMetadata read from the [__metadata__] section on the last load; null when the section was absent. See Migration.
Reloaded Event raised after a successful Reload() or ReloadAsync()
FileName The logical file name passed to ForFile()
LoadedFromPath Resolved absolute path from which the file was actually read
Dispose() Releases the file lock (if any) and stops the file-system watcher

IniConfigBuilder (fluent methods)

Method Description
AddSearchPath(path) Adds a directory to search for the INI file
AddSearchPaths(paths) Adds multiple directories at once
AddAppDataPath(applicationName) Adds %APPDATA%\applicationName (Linux: ~/.config/applicationName) as a search path; creates the directory if absent
SetWritablePath(path) Overrides the write target for new files when no existing file is found in any search path
AddDefaultsFile(path) Registers a file that supplies default values (applied before the user file)
AddConstantsFile(path) Registers a file that supplies admin-forced constants (applied last)
AddValueSource(source) Registers an IValueSource (sync) — applied after constants during both Build() and BuildAsync()
AddValueSource(asyncSource) Registers an IValueSourceAsync — applied after sync sources, only during BuildAsync() and ReloadAsync()
LockFile() Holds the file open read-exclusively for the process lifetime
MonitorFile([callback]) Installs a FileSystemWatcher; optional callback controls reload decision
WithEncoding(encoding) Sets the file encoding for reading and writing (default: UTF-8)
AutoSaveInterval(interval) Starts an internal timer that saves when HasPendingChanges() is true
SaveOnExit() Hooks AppDomain.CurrentDomain.ProcessExit to save on process termination
OnUnknownKey(callback) Registers a global UnknownKeyCallback invoked for keys that have no matching section property. Used for migration scenarios. See Migration.
EnableMetadata(version?, applicationName?) Opts in to writing a [__metadata__] section as the first section in the file on every save. Exposes IniConfig.Metadata to IAfterLoad hooks for version-gated migrations. See Migration.
EmptyWhenNull() Makes every reference-type property (string, list, array, dictionary) across all registered sections return an empty value instead of null when absent and no [DefaultValue] is set. See Empty-When-Null.
WithParserOptions(options) Applies a complete IniParserOptions object in one call, replacing any previously configured individual parser settings. See Parser-Options.
WithDuplicateKeyHandling(handling) Sets LastWins (default), FirstWins, or ThrowError for duplicate keys within the same section. See Parser-Options.
EnableQuotedValues() Strips surrounding "…" / '…' from values during parsing. See Parser-Options.
EnableEscapeSequences() Decodes \n, \t, \\, \xHH, and other C-style escape sequences in values. See Parser-Options.
EnableLineContinuation() Joins lines ending with \ to the following line, forming multi-line values. See Parser-Options.
CaseSensitiveKeys() Makes key-name lookup ordinal case-sensitive within sections. See Parser-Options.
CaseSensitiveSections() Makes section-name lookup ordinal case-sensitive. See Parser-Options.
RegisterSection<T>(impl) Registers a section with its generated implementation
AddListener(listener) Registers an IIniConfigListener for diagnostic events (file loaded/not found/saved/reloaded, unknown keys, conversion failures, errors). Zero overhead when no listener is registered. See Listeners.
Create() Creates and registers the IniConfig without loading any files. Enables plugin sections to be added via AddSection<T>() before the first Load(). See Plugin-Registrations.
Build() Loads the file synchronously, fires hooks, and registers the config in the global registry
BuildAsync(ct) Async variant of Build(); also applies IValueSourceAsync sources and calls async lifecycle hooks. Registers in the global registry and sets InitialLoadTask before I/O starts, enabling DI fire-and-forget patterns

IIniSection

All generated section classes implement IIniSection:

Member Description
HasChanges true when the section has been modified since the last load or save
SectionName The INI section name ([SectionName])
IsConstant(key) true when the value for key was loaded from a constants file and is therefore protected against modification. Use in UI code to disable the corresponding input control. See Runtime-Only-and-Constants.
GetRawValue(key) Returns the raw string value stored for key, or null if absent
SetRawValue(key, value) Stores a raw string value; throws AccessViolationException when key is constant
ResetToDefaults() Resets all properties (including runtime-only properties) to their compiled defaults
GetKeys() Enumerates the declared property key names. Source-generated sections return the compile-time property list; non-generated sections return the keys currently in the raw backing store. See Generic-Access.
GetPropertyType(key) Returns the .NET Type for the property identified by key, or null when the key is not a declared property. See Generic-Access.

LanguageConfigRegistry

LanguageConfigRegistry is a thread-safe global registry for language configurations. It mirrors IniConfigRegistry exactly — including the .ini-optional basename convention and the no-arg convenience overloads.

Method Description
ForFile(basename) Returns a fluent LanguageConfigBuilder. The .ini extension is stripped if present. Preferred entry point over LanguageConfigBuilder.ForBasename().
Get(basename) Returns the LanguageConfig for the given basename; throws KeyNotFoundException if not registered
Get() Returns the single registered LanguageConfig. Throws InvalidOperationException when zero or more than one config is registered.
TryGet(basename, out config) Returns false if not registered
GetSection<T>(basename) Shortcut for Get(basename).GetSection<T>()
GetSection<T>() Shortcut for Get().GetSection<T>() — works only when exactly one language config is registered
Unregister(basename) Removes a registration (useful in tests)
Clear() Removes all registrations (useful in tests)

Typical usage

// Startup — register via LanguageConfigRegistry (preferred)
LanguageConfigRegistry.ForFile("myapp")        // "myapp" and "myapp.ini" are equivalent
    .AddSearchPath(langDir)
    .WithBaseLanguage("en-US")
    .RegisterSection<IMainLanguage>(new MainLanguageImpl())
    .Build();

// Anywhere in the app — single-registration shorthand
var lang = LanguageConfigRegistry.GetSection<IMainLanguage>();

// Or with an explicit basename when multiple language configs are registered:
var lang = LanguageConfigRegistry.GetSection<IMainLanguage>("myapp");

LanguageConfigBuilder.Build() / BuildAsync() register into LanguageConfigRegistry automatically, so ForBasename() and ForFile() produce registry entries in the same way.


See also

  • Plugin-RegistrationsCreate() + AddSection<T>() + Load() for plugin-based apps
  • Migration — unknown-key callbacks, IUnknownKey<TSelf>, EnableMetadata, and version-gated upgrades
  • Loading-Configuration — builder method examples
  • ReloadingReload() / ReloadAsync() and HasPendingChanges()
  • SavingSave() / SaveAsync() and save hooks
  • Singleton-and-DIGetSection<T>() and the singleton guarantee
  • Async-Support — full async API guide
  • InternationalizationLanguageConfigRegistry, language packs, and i18n builder API
  • Parser-OptionsIniParserOptions — duplicate-key handling, quoted values, escape sequences, line continuation, case sensitivity
  • Empty-When-NullEmptyWhenNull() builder method and property/section-level equivalents
  • Generic-AccessGetSections(), GetSection(name), GetKeys(), and GetPropertyType() for dynamic meta-model inspection

Clone this wiki locally