Skip to content

3. API reference

Stratis Dermanoutsos edited this page Jun 22, 2026 · 1 revision

1. Abstractions

ITemplateService

The single entry point for replacing placeholders. It dispatches to every registered plugin.

public interface ITemplateService
{
    string ReplacePlaceholders(string? template, params object?[] inputs);
}

Members:

  • ReplacePlaceholders: Replaces every placeholder in template for which a registered plugin can produce a value. Unmatched placeholders are left untouched.
    • template: The template to process. A null or empty template returns string.Empty.
    • inputs: Optional context values. For each non-null entry of runtime type T, all ITemplatePlugin<T> registered for that exact T are invoked.

Dispatch order:

  1. Every registered ITemplatePlugin (tag-only) runs against the template.
  2. For each non-null input, every ITemplatePlugin<TInput> registered for the input's exact runtime type runs against the result.

The default implementation is TemplateService, registered as scoped by AddStringTemplates().

ITemplatePlugin

A plugin that resolves placeholders of a single tag without any external context.

public interface ITemplatePlugin
{
    protected string PlaceholderTag { get; }

    protected Regex PlaceholderRegex => PlaceholderHelper.BuildRegex(PlaceholderTag);

    protected string? GetValueOrDefault(string placeholder);

    string ReplacePlaceholders(string? template);
}

Members:

  • PlaceholderTag: (abstract) The tag used to identify placeholders handled by this plugin, e.g. "System".
  • PlaceholderRegex: The regex used to find this plugin's placeholders. Defaults to a compiled regex built from PlaceholderTag; override only for advanced scenarios.
  • GetValueOrDefault: (abstract) Returns the replacement value for placeholder (the key without the surrounding {{#Tag# … #Tag#}}), or null to leave the placeholder untouched.
  • ReplacePlaceholders: Replaces every placeholder of this plugin's tag in template. Provided by default; you do not implement it.

ITemplatePlugin<TInput>

A plugin that resolves placeholders of a single tag using a context object as input.

public interface ITemplatePlugin<in TInput> where TInput : class
{
    protected string PlaceholderTag { get; }

    protected Regex PlaceholderRegex => PlaceholderHelper.BuildRegex(PlaceholderTag);

    protected string? GetValueOrDefault(string placeholder, TInput? input);

    string ReplacePlaceholders(string? template, TInput? input);
}

Members:

  • PlaceholderTag: (abstract) The tag used to identify placeholders handled by this plugin, e.g. "Dictionary".

  • PlaceholderRegex: As above.

  • GetValueOrDefault: (abstract) Returns the replacement value for placeholder, using input as context, or null to leave the placeholder untouched.

  • ReplacePlaceholders: Replaces every placeholder of this plugin's tag in template using input. Provided by default.

  • Type parameters:

    • TInput: The context object passed when resolving a placeholder. Constrained to reference types (class).

References:

  1. Custom plugins

2. Registration

AddStringTemplates

Extension method on IServiceCollection that wires up the library.

public static IServiceCollection AddStringTemplates(
    this IServiceCollection services,
    Action<StringTemplatesOptions>? configure = null);
  • Registers the default plugins (DictionaryTemplatePlugin, SystemTemplatePlugin).
  • Registers ITemplateService (as TemplateService) as scoped.
  • The optional configure callback exposes StringTemplatesOptions for registering additional plugins.
builder.Services.AddStringTemplates(options => options.AddPlugins(opts => opts
    .AddPluginsFrom(Assembly.GetExecutingAssembly())));

StringTemplatesOptions

Options exposed by AddStringTemplates. It intentionally exposes only plugin registration.

public sealed class StringTemplatesOptions
{
    public StringTemplatesOptions AddPlugins(Action<PluginOptions> configure);
}

Members:

  • AddPlugins: Opens a PluginOptions scope for registering plugins. Returns the same instance, for chaining.

PluginOptions

The plugin-registration surface available inside AddPlugins.

public sealed class PluginOptions
{
    public PluginOptions AddPluginSingleton<TPlugin>()
        where TPlugin : class, ITemplatePlugin;

    public PluginOptions AddPluginSingleton<TPlugin, TInput>()
        where TPlugin : class, ITemplatePlugin<TInput>
        where TInput : class;

    public PluginOptions AddPluginScoped<TPlugin, TInput>()
        where TPlugin : class, ITemplatePlugin<TInput>
        where TInput : class;

    public PluginOptions AddPluginsFrom(params Assembly[] assemblies);
}

Members:

  • AddPluginSingleton<TPlugin>: Registers a tag-only (ITemplatePlugin) plugin as a singleton.
  • AddPluginSingleton<TPlugin, TInput>: Registers an input-driven (ITemplatePlugin<TInput>) plugin as a singleton.
  • AddPluginScoped<TPlugin, TInput>: Registers an input-driven plugin as scoped (use this when the plugin has scoped dependencies).
  • AddPluginsFrom: Scans the given assemblies for concrete plugin implementations and registers each one as a singleton against every plugin interface it implements.

All methods return the same PluginOptions instance, so calls can be chained.

Registrations use TryAddEnumerable, so the same plugin type is never registered twice.

References:

  1. IServiceCollection
  2. Plugins

3. Default plugin implementations

Shipped in the core StringTemplates package and registered automatically. See Default plugins for the full key tables.

SystemTemplatePlugin

public sealed class SystemTemplatePlugin : ITemplatePlugin
{
    public string PlaceholderTag => "System";
    public string? GetValueOrDefault(string placeholder);
}

Resolves date/time-based values (e.g. Date.Now, Month, Year) using the invariant culture. Tag: System.

DictionaryTemplatePlugin

public sealed class DictionaryTemplatePlugin : ITemplatePlugin<Dictionary<string, object>>
{
    public string PlaceholderTag => "Dictionary";
    public string? GetValueOrDefault(string placeholder, Dictionary<string, object>? dictionary);
}

Looks each placeholder key up in the supplied dictionary and returns the value's ToString(), or null if the key is absent. Tag: Dictionary.


4. The placeholder format

Placeholders follow the pattern:

{{#Tag#Key#Tag#}}
  • Tag matches a plugin's PlaceholderTag.
  • Key is one or more \w+ segments separated by dots (.), e.g. Date.Now or KeyVault.Auth.ClientId.

Internally each plugin matches its placeholders with the regex:

\{\{#Tag#(\w+\.)*\w+#Tag#\}\}

The regex is compiled and cached per tag, so repeated calls are cheap.

Any placeholder for which the matching plugin returns null (or for which no plugin is registered) is left untouched in the output.

Clone this wiki locally