Invex.Rez.Configuration
1.1.0
See the version list below for details.
dotnet add package Invex.Rez.Configuration --version 1.1.0
NuGet\Install-Package Invex.Rez.Configuration -Version 1.1.0
<PackageReference Include="Invex.Rez.Configuration" Version="1.1.0" />
<PackageVersion Include="Invex.Rez.Configuration" Version="1.1.0" />
<PackageReference Include="Invex.Rez.Configuration" />
paket add Invex.Rez.Configuration --version 1.1.0
#r "nuget: Invex.Rez.Configuration, 1.1.0"
#:package Invex.Rez.Configuration@1.1.0
#addin nuget:?package=Invex.Rez.Configuration&version=1.1.0
#tool nuget:?package=Invex.Rez.Configuration&version=1.1.0
Rez
Rez is a small .NET library for resolving terse, nestable template text such as {name} and
{function(args)}. It is designed for application strings, configuration values, and other text
where a full template engine would be unnecessary. Rez takes inspiration from
Mustache, but uses curly-brace tokens that can be nested and
resolved recursively.
var resolver = new Resolver();
resolver.AddSource(new ResolverSource(new Dictionary<string, string> { { "name", "World" } }));
var greeting = resolver.Resolve("Hello, {name}!");
// greeting: "Hello, World!"
Packages
| Package | What it does |
|---|---|
| Invex.Rez | The core templating library: Resolver, ResolverSource, and ResolverStore. |
| Invex.Rez.Configuration | Integration with Microsoft.Extensions.Configuration and dependency injection. |
Features
- Variables.
{name}is replaced with its value. - Functions.
{repeat(abc,3)}invokes a function with the raw argument text. - Nesting.
{variable{number}}resolves inside-out, left-to-right. - Recursion. Resolved values may themselves contain placeholders, with a nesting limit of 4096.
- Escaping.
\{literal\}excludes braces from resolution (the backslashes are preserved in the output). - Pluggable sources. Layer any number of variable and function sources; the first non-null result wins.
- Graceful fallback. Unresolvable placeholders are left in the output unchanged, and
Resolve(null)returnsnull. - High performance. Pooled buffers and span-based parsing minimize allocations.
- Configuration integration. Resolve templates inside
Microsoft.Extensions.Configurationvalues.
Installation
Install the core package:
dotnet add package Invex.Rez
For Microsoft.Extensions.Configuration integration, install the additional package:
dotnet add package Invex.Rez.Configuration
Both packages target net10.0 and netstandard2.0. On netstandard2.0,
Invex.Rez depends on System.Buffers and System.Memory. Invex.Rez.Configuration depends on
Microsoft.Extensions.Configuration.Abstractions and
Microsoft.Extensions.DependencyInjection.Abstractions.
Quick start
using Invex.Rez.Abstraction;
using Invex.Rez.Implementation;
var resolver = new Resolver()
.AddSource(new ResolverSource(
new Dictionary<string, string>
{
["name"] = "World"
},
new Dictionary<string, Func<FunctionCall, string>>
{
["shout"] = call => (call.Args ?? string.Empty).ToUpperInvariant() + "!"
}));
var output = resolver.Resolve("{shout(hello)}, {name}! {unknown}");
// output: "HELLO!, World! {unknown}"
Usage
Variables and functions
Sources provide variables, functions, or both. Functions receive a FunctionCall whose Args
property contains all text between the parentheses; Rez does not split or trim arguments, so
parsing is owned by the function. Function delegates must return a non-null string; a source
returns null only when it cannot resolve a name and wants the next source to be queried.
var resolver = new Resolver()
.AddSource(new ResolverSource(new Dictionary<string, Func<FunctionCall, string>>
{
["shout"] = call => (call.Args ?? string.Empty).ToUpperInvariant() + "!"
}));
var output = resolver.Resolve("{shout(hello)}");
// output: "HELLO!"
See the Syntax Guide for the complete template language.
Source ordering and mutable values
ResolverSource is immutable and initialized with known values; ResolverStore is mutable and
replaces an existing entry when the same name is added. Sources are queried in registration order
for every placeholder and the first non-null result wins, so register overrides before defaults:
var overrides = new ResolverStore();
var defaults = new ResolverSource(new Dictionary<string, string> { ["env"] = "production" });
var resolver = new Resolver()
.AddSource(overrides)
.AddSource(defaults);
resolver.Resolve("{env}"); // "production"
overrides.AddVariable("env", "development");
resolver.Resolve("{env}"); // "development"
Use RemoveVariable and RemoveFunction to remove entries from a ResolverStore. Resolver and
source types are not synchronized; configure them before concurrent use, or provide
synchronization when mutating them. See
Getting Started.
Configuration integration
Invex.Rez.Configuration provides two related features:
ConfigResolverSourceexposesIConfigurationRootvalues as Rez variables, including nested keys such as{Logging:Level}.IResolvableConfigwraps configuration and resolves templates when values are read. TheAddResolvableConfiguration()extension registers it in dependency injection. Values written through it are stored unmodified; resolution occurs on read.
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var resolver = new Resolver()
.AddSource(new ConfigResolverSource(config));
var output = resolver.Resolve("The {ServiceName} service is ready.");
See Configuration Integration for dependency-injection setup.
Custom sources
Implement IResolverSource to pull values from anywhere: environment variables, a database, or
computed values. Return null for names the source does not know so the next source is queried.
See the Developer Guide.
Documentation
Full documentation: https://invex-games.github.io/rez/
| Guide | Contents |
|---|---|
| Introduction | What Rez is, when to use it, and its key concepts |
| Getting Started | Install and resolve your first template |
| Syntax Guide | The complete template language reference |
| Examples | Worked examples from simple to advanced |
| Configuration Integration | Resolving templates in app configuration |
| Developer Guide | Abstractions, custom sources, and how resolution works |
| API Reference | Generated reference for every public type |
Development
The repository requires the .NET 10 SDK selected by global.json:
dotnet build Invex.Rez.slnx
dotnet test Invex.Rez.slnx
Build and preview the documentation site with the Atom build:
atom BuildDocs
atom ServeDocs
See AGENTS.md for repository structure, code conventions, generated workflow rules, snapshot testing, and the complete contributor checklist.
Where did the name come from?
The name Rez is a play on the word "res" (short for "resolution"), which is the process of resolving a template. The name was chosen as it is short and memorable and is not too similar to other names in the .NET ecosystem.
License
Rez is licensed under the MIT License. See LICENSE.txt.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Invex.Rez (>= 1.1.0)
- JetBrains.Annotations (>= 2026.2.0)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.13)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.13)
-
net10.0
- Invex.Rez (>= 1.1.0)
- JetBrains.Annotations (>= 2026.2.0)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.13)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.13)
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 |
|---|---|---|
| 1.2.0-rc.2 | 38 | 10/30/2026 |
| 1.1.0 | 85 | 10/22/2026 |
| 1.1.0-rc.6 | 51 | 10/22/2026 |
| 1.1.0-rc.4 | 56 | 10/22/2026 |
| 1.1.0-rc.2 | 50 | 10/16/2026 |
| 1.0.0 | 88 | 10/15/2026 |
| 0.4.0-rc.34 | 53 | 10/15/2026 |
| 0.4.0-rc.32 | 51 | 10/14/2026 |
| 0.4.0-rc.26 | 45 | 10/14/2026 |
| 0.4.0-rc.24 | 47 | 10/14/2026 |
| 0.4.0-rc.22 | 43 | 10/14/2026 |
| 0.4.0-rc.20 | 73 | 10/14/2026 |
| 0.4.0-rc.16 | 51 | 10/13/2026 |
| 0.4.0-rc.10 | 63 | 9/11/2026 |
| 0.4.0-rc.8 | 73 | 8/28/2026 |
| 0.4.0-rc.6 | 78 | 8/21/2026 |
| 0.4.0-rc.4 | 82 | 8/14/2026 |
| 0.4.0-rc.2 | 84 | 8/7/2026 |
| 0.3.0 | 124 | 8/3/2026 |
| 0.3.0-rc.5 | 79 | 8/3/2026 |