ConfigurationPlaceholders 2.0.0

dotnet add package ConfigurationPlaceholders --version 2.0.0
NuGet\Install-Package ConfigurationPlaceholders -Version 2.0.0
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="ConfigurationPlaceholders" Version="2.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add ConfigurationPlaceholders --version 2.0.0
#r "nuget: ConfigurationPlaceholders, 2.0.0"
#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.
// Install ConfigurationPlaceholders as a Cake Addin
#addin nuget:?package=ConfigurationPlaceholders&version=2.0.0

// Install ConfigurationPlaceholders as a Cake Tool
#tool nuget:?package=ConfigurationPlaceholders&version=2.0.0

Icon

ConfigurationPlaceholders

Latest Release Latest Pre-Release Downloads License Build

Adds support for placeholders in any configuration source (e.g. appsettings.json).

Getting started

Install the ConfigurationPlaceholders package from NuGet:

Package manager:

Install-Package ConfigurationPlaceholders

Or via the .NET CLI

dotnet add package ConfigurationPlaceholders

You can add ConfigurationPlaceholders to your project with the AddConfigurationPlaceholders extension method.

 var builder = WebApplication.CreateBuilder( args ); 
 builder 
     .AddConfigurationPlaceholders( new InMemoryPlaceholderResolver( new Dictionary<String, String?> 
     { 
         { "FQDN", fullDomainName } 
     } ) ); 

This will replace the placeholder ${FQDN} with the fully qualified name of the machine running the application.
Placeholder in the appsettings.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "CertificateSubject": "${FQDN}"
}

You can specify any number of placeholder resolvers IPlaceholderResolver in the call to AddConfigurationPlaceholders.
Later added placeholder resolvers IPlaceholderResolver will override values from before added placeholder resolvers IPlaceholderResolver.

Placeholder verification

By default ConfigurationPlaceholders will check if values are provided for all placeholders. If there are any missing placeholder values a ConfigurationPlaceholderMissingException will be thrown.
You can change this behavior by passing another MissingPlaceholderValueStrategy to AddConfigurationPlaceholders.

The following strategies are available:

VerifyAllAtStartup (default)

Will check if values are provided for all placeholders. If there are any missing placeholder values a ConfigurationPlaceholderMissingException will be thrown.

Throw

You can think of this one as a lazy execution version of VerifyAllAtStartup.   A ConfigurationPlaceholderMissingException will be thrown when a configuration entry with a missing placeholder value is being accessed. If the value never gets accessed, no exception will be thrown.

UseEmptyValue

Placeholders for which no value is provided will be replaced with an empty string.
"Hello, ${MissingValue}" will result in "Hello, "

IgnorePlaceholder

Placeholders for which no value is provided will not be replaced. The resulting value will still contain the placeholder. "Hello, ${MissingValue}" will result in "Hello, ${MissingValue}"

Examples

You can find some examples using ConfigurationPlaceholders here

Available placeholder resolvers IPlaceholderResolver

InMemoryPlaceholderResolver

Resolves placeholder values from an in-memory lookup. Works similar like the AddInMemoryCollection configuration source.

new InMemoryPlaceholderResolver( new Dictionary<String, String?>
{
    { "ApplicationName", Assembly.GetExecutingAssembly().GetName().Name },
    { "ApplicationVersion", Assembly.GetExecutingAssembly().GetName().Version!.ToString() }
} )
CallbackPlaceholderResolver

Resolves placeholder values by invoking user provided value factories.

new CallbackPlaceholderResolver( new Dictionary<String, Func<String?>>
{
    { "Time", () => DateTime.Now.ToString( "HH:mm:ss.fff" ) }
} )
ConfigurationPlaceholderResolver

Searches for values in all configuration sources matching the placeholder key.

new ConfigurationPlaceholderResolver()

In this example LocalDb is build based on other values in appsettings.json:

{
  "Lookup": {
    "DataDir": "X:/Temp/",
    "DbDir": "${Lookup:DataDir}db/"
  },
  "LocalDb": "${Lookup:DbDir}store.db"
}
EnvironmentVariableResolver

Resolves placeholder values by searching for environment variables matching the placeholder key. The search is performed in this priority order:

  1. EnvironmentVariableTarget.Process
  2. EnvironmentVariableTarget.User
  3. EnvironmentVariableTarget.Machine
new EnvironmentVariableResolver()
Custom providers

You can add your own placeholder resolvers by implementing IPlaceholderResolver. Potential sources could be REST APIs, files, secret stores etc...

How to add ConfigurationPlaceholders to your application

Different application setups require different ways to add ConfigurationPlaceholders.

WebApplication / minimal API
var builder = WebApplication.CreateBuilder( args );
builder
    .AddConfigurationPlaceholders( new InMemoryPlaceholderResolver( new Dictionary<String, String?>
    {
        { "FQDN", fullDomainName }
    } ) );
IHostBuilder / "old" ASP.NET / generic host
Host
    .CreateDefaultBuilder( args )
    .AddConfigurationPlaceholders( new InMemoryPlaceholderResolver( new Dictionary<String, String?>
    {
        { "FQDN", fullDomainName }
    } ) )
ConfigurationBuilder / console application
var configuration = new ConfigurationBuilder()
                    .AddJsonFile( "appsettings.json" )
                    ....
                    .AddConfigurationPlaceholders( new List<IPlaceholderResolver>
                    {
                        new InMemoryPlaceholderResolver( new Dictionary<String, String?>
                        {
                            {
                                "ApplicationName", Assembly.GetExecutingAssembly().GetName().Name
                            }
                        }
                        } ),
                        new EnvironmentVariableResolver()
                    } )
                    .Build();

Recursive placeholders

You can reference values containing placeholders from placeholders...

{
  "Lookup": {
    "SinksNs": "Serilog.Sinks",
    "DataDir": "X:/Temp/",
    "LogDir": "${Lookup:DataDir}logs/",
    "DbDir": "${Lookup:DataDir}db/"
  },
  "Serilog": {
    "Using": [ "${Lookup:SinksNs}.Console", "${Lookup:SinksNs}.File" ],
    "MinimumLevel": "Debug",
    "WriteTo": [
      { "Name": "Console" },
      {
        "Name": "File",
        "Args": { "path": "${Lookup:LogDir}${ApplicationName}/${ApplicationName}-${ApplicationVersion}.log" }
      }
    ]
  },
  "Test": "Today is the ${Today} (${Day}) an it is ${Time} ${NoValueDefinedForThisOne}",
  "LocalDb": "${Lookup:DbDir}store.db"
}

In this example we can see several placeholders referencing values containing other placeholders.
E.g. ${Lookup:DbDir} will be resolved with the value ${Lookup:DataDir}db/ from Lookup:DbDir (using ConfigurationPlaceholderResolver). ${Lookup:DataDir} is another placeholder which will be replaced with the value of Lookup:DataDirX:/Temp/.

You can combine values from multiple IPlaceholderResolver with multiple configuration sources.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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. 
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
2.0.0 277 1/17/2024
2.0.0-preview 68 1/17/2024
1.0.4 15,433 12/10/2022
1.0.4-preview-nugetMetaData 102 12/10/2022
1.0.4-preview-net8 60 1/17/2024
1.0.4-preview-multiTarget 106 12/10/2022
1.0.3 286 12/10/2022
1.0.3-preview-PRtest 111 12/10/2022
1.0.2 286 12/10/2022
1.0.2-preview-PRtest 112 12/10/2022
1.0.2-preview-doc 118 12/9/2022
1.0.1 285 12/9/2022
1.0.1-preview-f1 116 12/9/2022
1.0.1-preview-doc 118 12/9/2022
1.0.0-preview-f1 113 12/9/2022