ASTTemplateParser 1.0.42

There is a newer version of this package available.
See the version list below for details.
dotnet add package ASTTemplateParser --version 1.0.42
                    
NuGet\Install-Package ASTTemplateParser -Version 1.0.42
                    
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="ASTTemplateParser" Version="1.0.42" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ASTTemplateParser" Version="1.0.42" />
                    
Directory.Packages.props
<PackageReference Include="ASTTemplateParser" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ASTTemplateParser --version 1.0.42
                    
#r "nuget: ASTTemplateParser, 1.0.42"
                    
#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.
#:package ASTTemplateParser@1.0.42
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ASTTemplateParser&version=1.0.42
                    
Install as a Cake Addin
#tool nuget:?package=ASTTemplateParser&version=1.0.42
                    
Install as a Cake Tool

AST Template Parser

NuGet License

A high-performance, security-hardened template parser for .NET with HTML-like syntax. Works on .NET Standard 2.0, .NET Framework 4.8, .NET 6.0, and .NET 8.0.

✨ Features

  • 🚀 High Performance - 90,000+ renders/second with compiled property accessors
  • 🔒 Enterprise Security - Built-in XSS, injection, and DoS protection
  • 🧩 Component System - Reusable components with dynamic parameters
  • 📐 Layout System - Master page layouts with sections
  • 📝 HTML-like Syntax - No special directives needed, pure HTML tags
  • 🔄 Auto Cache - Component files automatically reload when modified
  • 🎯 Pre-Render Extraction - Extract Include names before rendering for cache lookup
  • 📁 Folder Components - Support block/projects/default.html structure
  • 🛡️ Param Defaults - Fallback values when variables are null
  • 🔔 OnBeforeIncludeRender - Event callback before each component renders
  • 🎁 OnAfterIncludeRender - Event callback to wrap/modify rendered output
  • 🏷️ Type-Specific Tags - <Element>, <Block>, <Data>, <Nav> with auto path prefix
  • 📄 Pages Directory - Separate directory for page templates with RenderPage()
  • 🔤 Case-Sensitive Tags - Template tags are PascalCase, HTML tags preserved
  • 🔁 Template Fragments - <Define> and <Render> for inline recursion
  • Smart If Conditions - Collections, objects, and nulls evaluated correctly
  • 🧱 BlockParser - Extract block info from page templates for database storage
  • Callback SetVariable Priority - Variables set in callback override Param values (NEW in v1.0.20!)
  • 🌐 Global Variables - Set static variables once for all engine instances (NEW in v1.0.35!)
  • 🌍 Cross-Platform - Works on Windows, Linux, and macOS

📦 Installation

NuGet Package Manager:

Install-Package ASTTemplateParser

.NET CLI:

dotnet add package ASTTemplateParser

🚀 Quick Start (5 Minutes)

Step 1: Create the Engine

using ASTTemplateParser;

var engine = new TemplateEngine();

Step 2: Set Your Data

// Simple variables
engine.SetVariable("UserName", "John");
engine.SetVariable("IsLoggedIn", true);

// Objects with properties
engine.SetVariable("User", new {
    Name = "John Doe",
    Email = "john@example.com",
    IsAdmin = false
});

// Lists for loops
engine.SetVariable("Products", new List<object> {
    new { Name = "Laptop", Price = 999.99 },
    new { Name = "Mouse", Price = 29.99 }
});

Step 3: Write Your Template

<Element template="page">
    <h1>Welcome, {{UserName}}!</h1>
    
    <If condition="IsLoggedIn">
        <p>Hello {{User.Name}}, your email is {{User.Email}}</p>
    <Else>
        <p>Please log in to continue.</p>
    </If>
    
    <h2>Our Products</h2>
    <ul>
        <ForEach var="product" in="Products">
            <li>{{product.Name}} - ${{product.Price}}</li>
        </ForEach>
    </ul>
</Element>

Step 4: Render!

string html = engine.Render(template);
Console.WriteLine(html);

Step 5: Global Variables (Optional)

// Set once at startup
TemplateEngine.SetGlobalVariable("SiteName", "My Website");

// Now available in ALL engine instances automatically
var engine2 = new TemplateEngine();
engine2.Render("Welcome to {{SiteName}}"); 

📖 Template Syntax Guide

1. Variables (Interpolation)

Use {{variableName}} to display values:


<p>Hello, {{UserName}}!</p>


<p>Email: {{User.Email}}</p>


<p>City: {{Order.Customer.Address.City}}</p>

1.5 Global Variables (NEW in v1.0.35!)

Global variables are static and shared across ALL TemplateEngine instances. Perfect for site-wide settings like copyright year, site name, or API URLs.

// Set once (e.g., in Program.cs)
TemplateEngine.SetGlobalVariable("SiteName", "My Website");
TemplateEngine.SetGlobalVariable("CurrentYear", DateTime.Now.Year);

// Available in any engine instance without calling SetVariable() again
var engine = new TemplateEngine();
string html = engine.Render("© {{CurrentYear}} {{SiteName}}");

Priority Logic:

  1. Additional variables in Render() call (Highest)
  2. Instance variables via engine.SetVariable()
  3. Global variables via TemplateEngine.SetGlobalVariable() (Lowest)

2. Conditionals (If/Else)

Show or hide content based on conditions:


<If condition="IsLoggedIn">
    <p>Welcome back!</p>
</If>


<If condition="IsAdmin">
    <button>Delete</button>
<Else>
    <button disabled>Delete (Admin only)</button>
</If>


<If condition="Role == 'admin'">
    <span>👑 Admin</span>
<ElseIf condition="Role == 'moderator'">
    <span>🛡️ Moderator</span>
<Else>
    <span>👤 User</span>
</If>

Supported Operators:

Operator Example Description
== Status == 'active' Equal to
!= Count != 0 Not equal to
> Age > 18 Greater than
< Stock < 10 Less than
>= Score >= 50 Greater or equal
<= Price <= 100 Less or equal
&& or and A && B Both must be true
|| or or A || B At least one true

3. Loops (ForEach)

Repeat content for each item in a collection:


<ul>
    <ForEach var="item" in="Items">
        <li>{{item}}</li>
    </ForEach>
</ul>


<table>
    <ForEach var="product" in="Products">
        <tr>
            <td>{{product.Name}}</td>
            <td>${{product.Price}}</td>
            <If condition="product.IsOnSale">
                <td class="sale">SALE!</td>
            </If>
        </tr>
    </ForEach>
</table>


<ForEach var="category" in="Categories">
    <h3>{{category.Name}}</h3>
    <ForEach var="item" in="category.Items">
        <p>{{item.Name}}</p>
    </ForEach>
</ForEach>

4. Components (Reusable Templates)

Create reusable UI pieces:

Create a component file (components/element/button.html):

<a href="{{href}}" class="btn btn-{{type}}">
    {{text}}
</a>

Use the component with static values:

<Include component="element/button">
    <Param name="text" value="Click Me" />
    <Param name="type" value="primary" />
    <Param name="href" value="/action" />
</Include>

Use with dynamic values:


<Include component="element/button">
    <Param name="text" value="{{ButtonText}}" />
    <Param name="type" value="{{ButtonType}}" />
    <Param name="href" value="/user/{{User.Id}}" />
</Include>


<Include component="element/button">
    <Param name="text" value="ButtonText" />
</Include>


<Include component="element/button">
    <Param name="text" value="Hello {{UserName}}!" />
</Include>

Param with Default Values (NEW in v1.0.5!):


<Include component="element/button">
    <Param name="text" value="{{ButtonText}}" default="Click Me" />
    <Param name="type" value="{{ButtonType}}" default="primary" />
</Include>


<Include component="element/header">
    <Param name="title" value="{{PageTitle}}" default="Welcome, {{UserName}}!" />
</Include>

Folder-Based Components (NEW in v1.0.5!):

components/
├── element/
│   └── button.html          ← component="element/button"
└── block/
    └── projects/            ← component="block/projects" (folder)
        └── default.html     ← Automatically loaded

<Include component="block/projects">
    <Param name="title" value="My Projects" />
</Include>

Setup components directory in C#:

engine.SetComponentsDirectory("./components");
engine.SetVariable("ButtonText", "Submit");
engine.SetVariable("UserName", "Alice");

5. Pre-Render Data Extraction (NEW in v1.0.4!)

Use name attribute on Include tags to identify components for cache lookup before rendering:


<Include component="element/header" name="header_abc123_cached">
    <Param name="class" value="{{element.Class}}" />
    <Param name="text" value="{{element.Content}}" />
</Include>

Extract Include names before rendering:

var template = @"<Include component=""element/header"" name=""header_abc123_cached"">
                    <Param name=""text"" value=""{{data.Title}}"" />
                 </Include>";

// Option 1: Simple extraction (AST is cached for later Render())
var includeInfos = TemplateEngine.ExtractIncludeNames(template);

foreach (var info in includeInfos)
{
    // info.Name = "header_abc123_cached" (your cache key!)
    // info.ComponentPath = "element/header"
    // info.Parameters = {"text": "{{data.Title}}"}
    
    var cachedData = YourCacheService.Get(info.Name);
    engine.SetVariable("data", cachedData);
}

// Render uses cached AST - NO performance penalty!
var html = engine.Render(template);

Most efficient approach with PrepareTemplate:

var engine = new TemplateEngine();

// Step 1: Prepare once - parse, validate, cache, extract names
var prepared = engine.PrepareTemplate(template);

// Step 2: Use extracted names to fetch cached data
foreach (var info in prepared.IncludeInfos)
{
    var cachedElement = YourCache.Get(info.Name);
    engine.SetVariable("element", cachedElement);
}

// Step 3: Render directly from prepared AST (FASTEST!)
var html = engine.RenderPrepared(prepared);

6. OnBeforeIncludeRender Event (NEW in v1.0.6!)

Get a callback before each Include component renders - perfect for dynamic data loading:

var engine = new TemplateEngine();
engine.SetComponentsDirectory("./components");

// Set callback - fires BEFORE each Include renders
engine.OnBeforeIncludeRender((info, eng) =>
{
    Console.WriteLine($"Rendering: {info.Name}");
    
    // Fetch data from cache using Include name as key
    var cachedData = YourCacheService.Get(info.Name);
    eng.SetVariable("element", cachedData);
});

// Render template - callback fires for each Include
var html = engine.Render(template);
IncludeInfo Property Description
Name Include name attribute (use as cache key)
ComponentPath Component path like block/slider
ComponentType Type: "element", "block", "data", "navigation", or "include"
Parameters Dictionary of Param names and values
SetVariable Priority in Callback (NEW in v1.0.20!)

Variables set via SetVariable() in callback take priority over Param values. This enables dynamic attribute injection:

engine.OnBeforeIncludeRender((info, eng) =>
{
    if (info.ComponentType == "element")
    {
        // Get existing attributes from Param
        var existingAttrs = info.Parameters.TryGetValue("attributes", out var val) ? val : "";
        
        // Inject additional data attributes
        var identity = GetElementIdentity(info.Name);
        var dataAttrs = $"data-identity='{identity}' data-editable='true'";
        
        // SetVariable takes priority over Param!
        eng.SetVariable("attributes", $"{existingAttrs} {dataAttrs}");
    }
});

Template (components/element/subTitle.html):

<h2 class="edit-able {{class}}" {{attributes}}>{{content}}</h2>

Usage:

<Element component="subTitle" name="my_subtitle">
    <Param name="class" value="highlight" />
    <Param name="content" value="Welcome!" />
    <Param name="attributes" value="id='main-title'" />
</Element>

Output (with callback injection):

<h2 class="edit-able highlight" id='main-title' data-identity='abc123' data-editable='true'>Welcome!</h2>

7. OnAfterIncludeRender Event (NEW in v1.0.7!)

Get a callback after each component renders - perfect for wrapping output:

engine.OnAfterIncludeRender((info, renderedHtml) =>
{
    // info.ComponentType tells you the type
    // Wrap based on component type
    if (info.ComponentType == "block")
    {
        return $"<section id=\"{info.Name}\">{renderedHtml}</section>";
    }
    return renderedHtml;
});

8. Type-Specific Component Tags (NEW in v1.0.7!)

Instead of <Include component="element/button">, use type-specific tags with auto path prefix:

Tag Path Prefix Example
<Element> element/ <Element component="button"> → loads element/button.html
<Block> block/ <Block component="slider"> → loads block/slider.html
<Data> data/ <Data component="schema"> → loads data/schema.html
<Nav> navigation/ <Nav component="menu"> → loads navigation/menu.html

<Include component="element/subTitle" name="my_subtitle">
    <Param name="content" value="Years Experience" />
</Include>


<Element component="subTitle" name="my_subtitle">
    <Param name="content" value="Years Experience" />
</Element>

⚠️ Important (v1.0.10+): Template tags MUST be PascalCase (<Section>, <Data>, <Element>).
Lowercase HTML tags like <section>, <div>, <nav> are preserved as-is.

9. Container Tags

Tag Purpose Example
<Element> Main content wrapper <Element template="page">...</Element>
<Data> Data section <Data section="meta">...</Data>
<Nav> Navigation section <Nav section="main">...</Nav>
<Block> Named block <Block name="footer">...</Block>

10. Pages Directory & RenderPage (NEW in v1.0.8!)

Separate your page templates from components with a dedicated pages directory:

var engine = new TemplateEngine();

// Setup both directories
engine.SetComponentsDirectory("./components");   // For reusable components
engine.SetPagesDirectory("./pages");             // For page templates

// Set your data
engine.SetVariable("PageTitle", "Home");
engine.SetVariable("UserName", "John");

// Render a page template
string html = engine.RenderPage("home");         // → pages/home.html

// Or with RenderFile using flag
string html2 = engine.RenderFile("about", isPage: true);   // → pages/about.html
string html3 = engine.RenderFile("element/button");        // → components/element/button.html

Directory Structure:

your-project/
├── components/              ← SetComponentsDirectory()
│   ├── element/
│   │   └── button.html
│   └── block/
│       └── footer.html
│
├── pages/                   ← SetPagesDirectory()
│   ├── home.html
│   ├── about.html
│   └── contact.html
│
└── Program.cs

Page Template Example (pages/home.html):

<Element template="home">
    <h1>{{PageTitle}}</h1>
    
    
    <Element component="header" name="main_header">
        <Param name="title" value="{{PageTitle}}" />
    </Element>
    
    <Block component="slider" name="hero">
        <Param name="slides" value="{{Slides}}" />
    </Block>
</Element>

11. Template Fragments: Define & Render (NEW in v1.0.11!)

Create reusable template fragments with inline recursion - perfect for multi-level navigation menus!


<Define name="menuItem">
    <li>
        <a href="{{menuNode.Url}}">{{menuNode.Title}}</a>
        <If condition="menuNode.Children">
            <ul>
                <ForEach var="child" in="menuNode.Children">
                    
                    <Render name="menuItem" menuNode="child" />
                </ForEach>
            </ul>
        </If>
    </li>
</Define>


<nav class="main-nav">
    <ul>
        <ForEach var="item" in="menuItems">
            <Render name="menuItem" menuNode="item" />
        </ForEach>
    </ul>
</nav>

C# Setup:

var menuItems = new List<object>
{
    new {
        Title = "Home",
        Url = "/",
        Children = new List<object>
        {
            new { Title = "About", Url = "/about", Children = (object)null },
            new { Title = "Services", Url = "/services", Children = (object)null }
        }
    }
};

engine.SetVariable("menuItems", menuItems);

Benefits:

  • ✅ Single file recursion - no separate component files needed
  • ✅ Supports unlimited depth (up to MaxRecursionDepth, default: 20)
  • ✅ Parameters passed via attributes
  • ✅ Variable interpolation works in parameters

12. Smart If Condition Truthiness (NEW in v1.0.11!)

If conditions now properly evaluate all types:

Value Result Example
null false <If condition="item.Children"> when Children is null
Empty string "" false <If condition="name"> when name is ""
Empty collection [] false <If condition="list"> when list has 0 items
Non-empty collection true <If condition="Children"> when Children has items
Any non-null object true <If condition="user"> when user exists
Boolean As-is <If condition="isActive">
<ul>
    <ForEach var="item" in="menuItems">
        <li>
            {{item.Title}}
            <If condition="item.Children">
                
                <ul>
                    <ForEach var="child" in="item.Children">
                        <li>{{child.Title}}</li>
                    </ForEach>
                </ul>
            <Else>
                
                <span>(No sub-items)</span>
            </If>
        </li>
    </ForEach>
</ul>

🧱 BlockParser: Page Template Block Extraction (NEW in v1.0.12!)

Parse Block-based page templates and extract block information for database storage. Perfect for CMS systems where you want to:

  • Store block configuration in database
  • Enable/disable blocks dynamically
  • Reorder blocks without editing template files

Block Template Format


<Block component="slider" name="slider">
    <Param name="iscustomstyle" value="true"/>
    <Param name="flag" value="slider"/>
</Block>

<Block component="about" name="about">
    <Param name="sectionClass" value="about-area grey-bg2 pt-100 pb-100"/>
    <Param name="iscustomstyle" value="true"/>
</Block>

<Block component="team" name="team">
    <Param name="sectionClass" value="team-area pt-125 pb-100"/>
    <Param name="style" value="background-image: url(assets/img/bg/01.jpg);"/>
</Block>

Parse and Save to Database

// Setup engine with pages directory
var engine = new TemplateEngine();
engine.SetPagesDirectory(@"D:\MyProject\Pages");
engine.SetComponentsDirectory(@"D:\MyProject\Components");

// Create BlockParser with engine
var blockParser = new BlockParser(engine);

// Option 1: Simple - just page name (uses PagesDirectory)
var blocks = blockParser.ParseBlocks("home-blocks");  // → pages/home-blocks.html

// Option 2: Full path (for custom locations)
// var blocks = blockParser.ParseBlocks(@"D:\Custom\home.html", "home");

// 2. Save to YOUR database (use your own EF/database code)
foreach (var block in blocks)
{
    _dbContext.PageBlocks.Add(new PageBlockEntity
    {
        Id = block.Id,
        Name = block.Name,                    // "slider"
        ComponentPath = block.ComponentPath,  // "slider"
        Order = block.Order,                  // 0, 1, 2...
        PageName = block.PageName,            // "home"
        ParametersJson = JsonSerializer.Serialize(block.Parameters)
    });
}
_dbContext.SaveChanges();

Load from Database and Render

// 3. Load blocks from database
var blocksFromDb = _dbContext.PageBlocks
    .Where(b => b.PageName == "home")
    .OrderBy(b => b.Order)
    .ToList();

// 4. Render each block's component from file
var engine = new TemplateEngine();
engine.SetComponentsDirectory(@"D:\Components");

var html = new StringBuilder();
foreach (var block in blocksFromDb)
{
    // ComponentPath renders from file (e.g., slider.html)
    html.Append(engine.RenderFile(block.ComponentPath));
}

return html.ToString();

BlockInfo Properties

Property Type Description
Id string Unique GUID
Name string Block name (e.g., "slider")
ComponentPath string Component file path for RenderFile()
Order int Display order (0, 1, 2...)
PageName string Page identifier
Parameters Dictionary<string, string> Block parameters (save as JSON)

Flow Diagram

┌─────────────────────────────────────────────────────────────────┐
│ FIRST RUN                                                       │
├─────────────────────────────────────────────────────────────────┤
│  Template File ──► ParseBlocks() ──► List<BlockInfo>           │
│                                           │                     │
│                                           ▼                     │
│                                    Save to Database             │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ SUBSEQUENT RUNS                                                 │
├─────────────────────────────────────────────────────────────────┤
│  Database ──► Load Blocks ──► RenderFile(ComponentPath)        │
│                                           │                     │
│                                           ▼                     │
│                                       HTML Output               │
└─────────────────────────────────────────────────────────────────┘

🔒 Security Features

The parser includes built-in protection against common attacks:

Default Protection (Automatic)

  • XSS Prevention - All output is HTML-encoded
  • Loop Limits - Maximum 1000 iterations (prevents DoS)
  • Recursion Limits - Maximum 10 component depth
  • Path Validation - Prevents directory traversal attacks

Custom Security Configuration

var security = new SecurityConfig
{
    MaxLoopIterations = 500,        // Limit loop iterations
    MaxRecursionDepth = 5,          // Limit component nesting
    MaxPropertyDepth = 10,          // Limit property chain depth
    HtmlEncodeOutput = true,        // Encode output (XSS protection)
    AllowMethodCalls = false,       // Block method invocation
    BlockedPropertyNames = new HashSet<string>
    {
        "Password", "Secret", "Token", "ConnectionString"
    }
};

var engine = new TemplateEngine(security);

📊 Performance

Template Size Operations/Second Memory
Small (1KB) ~7,000 ops/sec Low
Medium (4KB) ~1,600 ops/sec Medium
Large (8KB) ~800 ops/sec Higher

💡 Complete Example

using ASTTemplateParser;
using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // 1. Create engine
        var engine = new TemplateEngine();
        
        // 2. Set components directory (optional)
        engine.SetComponentsDirectory("./components");
        
        // 3. Set your data
        engine.SetVariable("PageTitle", "My Store");
        engine.SetVariable("User", new { Name = "Alice", IsVIP = true });
        engine.SetVariable("Products", new List<object>
        {
            new { Name = "Laptop", Price = 999, InStock = true },
            new { Name = "Tablet", Price = 499, InStock = false },
            new { Name = "Phone", Price = 699, InStock = true }
        });
        
        // 4. Define template
        var template = @"
<Element template=""store"">
    <h1>{{PageTitle}}</h1>
    
    <If condition=""User.IsVIP"">
        <div class=""vip-badge"">⭐ VIP Member: {{User.Name}}</div>
    </If>
    
    <div class=""products"">
        <ForEach var=""p"" in=""Products"">
            <div class=""product"">
                <h3>{{p.Name}}</h3>
                <p class=""price"">${{p.Price}}</p>
                <If condition=""p.InStock"">
                    <button>Add to Cart</button>
                <Else>
                    <span class=""out-of-stock"">Out of Stock</span>
                </If>
            </div>
        </ForEach>
    </div>
</Element>";
        
        // 5. Render and output
        string html = engine.Render(template);
        Console.WriteLine(html);
    }
}

🎯 Target Platforms

Platform Version Status
.NET Standard 2.0 ✅ Supported
.NET Framework 4.8 ✅ Supported
.NET 6.0 ✅ Supported
.NET 8.0 ✅ Supported

📄 License

MIT License - Free for personal and commercial use.


📚 Documentation

For complete documentation including Layout System, Advanced Components, and Slots, see DOCUMENTATION.md.


❓ FAQ

Q: How is this different from Razor? A: This uses pure HTML-like syntax (<If>, <ForEach>) instead of @ directives. It's faster and has no runtime compilation.

Q: Can I use this with ASP.NET Core? A: Yes! It works with any .NET platform that supports .NET Standard 2.0 or higher.

Q: Is it safe for user-generated templates? A: With proper SecurityConfig, yes. Enable strict mode for user templates.


Version 1.0.19 - January 2026

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  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.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 is compatible.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos 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.3 70 1/21/2026
2.0.2 72 1/20/2026
2.0.0 81 1/20/2026
1.0.45 93 1/19/2026
1.0.43 83 1/19/2026
1.0.42 78 1/19/2026
1.0.41 80 1/19/2026
1.0.40 80 1/19/2026
1.0.39 92 1/17/2026
1.0.38 76 1/15/2026
1.0.37 86 1/15/2026
1.0.36 88 1/15/2026
1.0.35 82 1/15/2026
1.0.33 81 1/14/2026
1.0.32 76 1/14/2026
1.0.31 88 1/14/2026
1.0.30 88 1/14/2026
1.0.29 100 1/14/2026
1.0.28 86 1/14/2026
1.0.27 91 1/14/2026
1.0.26 80 1/13/2026
1.0.25 84 1/13/2026
1.0.24 78 1/13/2026
1.0.23 76 1/13/2026
1.0.22 79 1/13/2026
1.0.21 83 1/13/2026
1.0.20 83 1/13/2026
1.0.19 81 1/12/2026
1.0.18 84 1/12/2026
1.0.17 86 1/12/2026
1.0.16 78 1/12/2026
1.0.15 76 1/12/2026
1.0.14 84 1/12/2026
1.0.13 76 1/12/2026
1.0.12 84 1/12/2026
1.0.11 83 1/11/2026
1.0.10 78 1/11/2026
1.0.9 85 1/10/2026
1.0.8 84 1/10/2026
1.0.7 85 1/10/2026
1.0.6 85 1/8/2026
1.0.5 85 1/8/2026
1.0.4 82 1/8/2026
1.0.3 83 1/7/2026
1.0.2 84 1/7/2026
1.0.1 86 1/7/2026
1.0.0 83 1/7/2026

v1.0.42 - (January 19, 2026)
- FIXED: Refined variable isolation logic. Now ensures parent variables (like 'element') are available during parameter resolution but are properly blocked from leaking into the child component's internal execution context.
- IMPROVED: Robustness of engine-to-evaluator variable synchronization.