Debugging
The {@} debug tag emits diagnostic content during template rendering without affecting the merged output. It routes through System.Diagnostics.Trace, so the destination is whichever trace listeners the host process has registered — by default, the Visual Studio / VS Code Output window.
Basic syntax
{@ expression }The expression follows the same rules as any other tag — bind expression, literal, declared variable, $ reference, or lambda call. The resolved value is written to all registered trace listeners.
Example
Data:
var data = new
{
FirstName = "John",
LastName = "Doe",
FavoriteColors = new[] { "Blue", "Red", "Green" }
};Template:
Hello {FirstName} {LastName},
Here is a list of your favorite colors:
{@ 'starting #each block for colors' }
{#each FavoriteColors}
{@ $ }
- {$}
{/each}
{@ 'completed #each block for colors' }Rendered output:
Hello John Doe,
Here is a list of your favorite colors:
- Blue
- Red
- GreenOutput window result:
starting #each block for colors
Blue
Red
Green
completed #each block for colorsAllowed expression forms
{@} accepts the same value forms as a lambda argument:
- String literals (single or double quoted) —
{@ 'note' } - Numeric literals —
{@ 42 } - Boolean literals —
{@ true } - Bound expressions —
{@ Address.City } $and scope-walk expressions —{@ $ },{@ ..\Title }- Declared variables —
{@ :counter } - Lambda return values —
{@ (Items) => summary }
String literal quoting follows the same rules as lambda arguments.
Redirecting trace output
By default, System.Diagnostics.Trace.Listeners contains a DefaultTraceListener that writes to the IDE Output window during a debug session. To route debug output elsewhere — a log file, a console, a structured logging sink — register a custom TraceListener:
Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
// or
Trace.Listeners.Add(new TextWriterTraceListener("debug.log"));See Microsoft’s TraceListeners documentation for the full list of built-in listeners and the contract for custom ones.
In production builds where TRACE is not defined, calls to Trace.WriteLine are compiled out — debug tags become no-ops without needing to be removed from templates. This makes {@} safe to leave in templates that ship to production.
When to use it
- Render-time inspection — see exactly what value a bind expression is producing, in context, without writing temporary output to the template.
- Loop tracing — emit the current
$on each iteration to confirm an{#each}is seeing the items you expect. - Variable observation — print a variable’s running value at key points in the template.
- Lambda verification — call a lambda from inside
{@}to log its return value without rendering it.
Whitespace
{@} is a non-simple tag, so it accepts - trim markers ({-@ … -}) and is affected by engine-level TrimWhitespace. See Whitespace Control.
Next steps
- Comments —
{!}is the static counterpart: notes for template authors that never reach the trace stream or output - Exception Handling — when something throws mid-merge, the exception context tells you exactly where to insert a
{@}to investigate - Lambda Expressions — debug tags pair well with lambdas that format or summarize complex values