-
-
Notifications
You must be signed in to change notification settings - Fork 0
3. API reference
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 intemplatefor which a registered plugin can produce a value. Unmatched placeholders are left untouched.-
template: The template to process. Anullor empty template returnsstring.Empty. -
inputs: Optional context values. For each non-null entry of runtime typeT, allITemplatePlugin<T>registered for that exactTare invoked.
-
Dispatch order:
- Every registered
ITemplatePlugin(tag-only) runs against the template. - For each non-null
input, everyITemplatePlugin<TInput>registered for the input's exact runtime type runs against the result.
The default implementation is
TemplateService, registered as scoped byAddStringTemplates().
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 fromPlaceholderTag; override only for advanced scenarios. -
GetValueOrDefault: (abstract) Returns the replacement value forplaceholder(the key without the surrounding{{#Tag# … #Tag#}}), ornullto leave the placeholder untouched. -
ReplacePlaceholders: Replaces every placeholder of this plugin's tag intemplate. Provided by default; you do not implement it.
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 forplaceholder, usinginputas context, ornullto leave the placeholder untouched. -
ReplacePlaceholders: Replaces every placeholder of this plugin's tag intemplateusinginput. Provided by default. -
Type parameters:
-
TInput: The context object passed when resolving a placeholder. Constrained to reference types (class).
-
References:
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(asTemplateService) as scoped. - The optional
configurecallback exposesStringTemplatesOptionsfor registering additional plugins.
builder.Services.AddStringTemplates(options => options.AddPlugins(opts => opts
.AddPluginsFrom(Assembly.GetExecutingAssembly())));Options exposed by AddStringTemplates. It intentionally exposes only plugin registration.
public sealed class StringTemplatesOptions
{
public StringTemplatesOptions AddPlugins(Action<PluginOptions> configure);
}Members:
-
AddPlugins: Opens aPluginOptionsscope for registering plugins. Returns the same instance, for chaining.
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
PluginOptionsinstance, so calls can be chained.Registrations use
TryAddEnumerable, so the same plugin type is never registered twice.
References:
Shipped in the core
StringTemplatespackage and registered automatically. See Default plugins for the full key tables.
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.
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.
Placeholders follow the pattern:
{{#Tag#Key#Tag#}}
-
Tagmatches a plugin'sPlaceholderTag. -
Keyis one or more\w+segments separated by dots (.), e.g.Date.NoworKeyVault.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.
Copyright © Stratis Dermanoutsos 2025-2026