GrimoireConfigurationClient implements both IConfigurationSource and IConfigurationProvider, integrating Grimoire seamlessly into the standard .NET configuration pipeline.
1
2
3
4
5
6
7
8
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddGrimoire(
baseUrl: "http://localhost:8080",
apiKey: "grm_your_api_key_here",
environment: "production"
);
That’s it. All configuration entries for the production environment are loaded into builder.Configuration and available through the standard IConfiguration interface.
AddGrimoire() calls builder.Configuration.Add(new GrimoireConfigurationClient(...)), which:
IConfiguration is first built, calls Load() synchronouslyLoad() calls GET /api/consumer/configurations?environment={env}{ key, value } pairsData dictionary (inherited from ConfigurationProvider)The configuration is loaded once at startup. It is not reloaded dynamically. If you need live config refresh, restart the application or implement a custom IConfigurationProvider that polls on a timer.
1
2
3
4
5
6
7
8
9
// After AddGrimoire(), use IConfiguration as normal:
var dbHost = builder.Configuration["Database:Host"];
var maxRetry = builder.Configuration.GetValue<int>("MaxRetries");
var featureOn = builder.Configuration.GetValue<bool>("Feature:DarkMode");
// Works with IOptions<T> too
builder.Services.Configure<DatabaseOptions>(
builder.Configuration.GetSection("Database")
);
Grimoire keys map directly to the IConfiguration key hierarchy:
| Grimoire key | .NET access |
|---|---|
Database:Host |
config["Database:Host"] |
Database:Port |
config.GetSection("Database")["Port"] |
Feature:DarkMode |
config.GetValue<bool>("Feature:DarkMode") |
MaxRetries |
config.GetValue<int>("MaxRetries") |
AddGrimoire() adds the Grimoire source at the end of the configuration pipeline. This means:
appsettings.json and appsettings.{Environment}.jsonTo change priority, call AddGrimoire() earlier or later in the chain.
The GrimoireConfigurationClient also exposes async methods for use outside the configuration pipeline:
1
2
3
4
5
6
7
8
// Inject or instantiate the client directly
var client = new GrimoireConfigurationClient(baseUrl, apiKey, environment);
// Get a single key
string? value = await client.GetAsync("Feature:DarkMode");
// Get all keys as a dictionary
IReadOnlyDictionary<string, string> all = await client.GetAllAsync();
If the Grimoire API is unavailable at startup, Load() will throw an HttpRequestException, which will prevent the application from starting. This is intentional — a service that cannot read its configuration should not start.
To tolerate failures (e.g. during local development without Grimoire), wrap the call:
1
2
3
4
5
6
7
8
9
try
{
builder.Configuration.AddGrimoire(baseUrl, apiKey, environment);
}
catch (HttpRequestException)
{
// Grimoire unavailable — fall back to local config only
Console.Error.WriteLine("Warning: Grimoire unreachable, using local config");
}