Skip to main content Link Search Menu Expand Document (external link)

Variables & Params

Store, reuse, and pass data throughout your PDF templates using parameters and calculated values.


Learning Objectives

By the end of this article, you’ll be able to:

  • Set and use document parameters via doc.Params
  • Pass data from C# to templates
  • Create calculated values and reuse them
  • Understand parameter scope and lifetime
  • Use global vs local parameters
  • Organize complex data structures

Document Parameters (doc.Params)

The doc.Params dictionary is the primary way to pass data from C# to your templates.

Basic Usage

var doc = Document.ParseDocument("template.html");

// Set a single parameter
doc.Params["title"] = "Monthly Report";

// Set multiple parameters
doc.Params["author"] = "John Doe";
doc.Params["date"] = DateTime.Now;
doc.Params["pageCount"] = 10;

doc.SaveAsPDF("output.pdf");

Template:

<h1>{{title}}</h1>
<p>Author: {{author}}</p>
<p>Date: {{format(date, 'yyyy-MM-dd')}}</p>
<p>Pages: {{pageCount}}</p>

Passing Complex Objects

Anonymous Objects

doc.Params["model"] = new
{
    customerName = "Acme Corporation",
    invoiceNumber = "INV-2025-001",
    date = DateTime.Now,
    items = new[]
    {
        new { description = "Widget A", quantity = 5, price = 10.00 },
        new { description = "Widget B", quantity = 3, price = 15.00 }
    },
    total = 95.00
};

Template:

<h1>Invoice #{{model.invoiceNumber}}</h1>
<p>Customer: {{model.customerName}}</p>
<p>Date: {{format(model.date, 'MMMM dd, yyyy')}}</p>

<table>
    {{#each model.items}}
    <tr>
        <td>{{this.description}}</td>
        <td>{{this.quantity}}</td>
        <td>${{this.price}}</td>
    </tr>
    {{/each}}
</table>

<p><strong>Total: ${{model.total}}</strong></p>

Typed Classes

public class Invoice
{
    public string InvoiceNumber { get; set; }
    public string CustomerName { get; set; }
    public DateTime Date { get; set; }
    public List<InvoiceItem> Items { get; set; }
    public decimal Total { get; set; }
}

public class InvoiceItem
{
    public string Description { get; set; }
    public int Quantity { get; set; }
    public decimal Price { get; set; }
}

// Usage
var invoice = new Invoice
{
    InvoiceNumber = "INV-2025-001",
    CustomerName = "Acme Corporation",
    Date = DateTime.Now,
    Items = new List<InvoiceItem>
    {
        new InvoiceItem { Description = "Widget A", Quantity = 5, Price = 10.00m },
        new InvoiceItem { Description = "Widget B", Quantity = 3, Price = 15.00m }
    },
    Total = 95.00m
};

doc.Params["model"] = invoice;

Multiple Parameters

You can set multiple independent parameters:

// Company info
doc.Params["company"] = new
{
    name = "Tech Corp",
    address = "123 Main St",
    phone = "555-1234"
};

// Report data
doc.Params["report"] = new
{
    title = "Q4 Sales",
    period = "2024 Q4",
    data = salesData
};

// User info
doc.Params["currentUser"] = new
{
    name = "John Doe",
    role = "Manager"
};

// Configuration
doc.Params["config"] = new
{
    showHeader = true,
    showFooter = true,
    includeCharts = false
};

Template:

<div class="header">
    <h1>{{company.name}}</h1>
    <p>{{company.address}} | {{company.phone}}</p>
</div>

<h2>{{report.title}}</h2>
<p>Period: {{report.period}}</p>
<p>Generated by: {{currentUser.name}} ({{currentUser.role}})</p>

{{#if config.showHeader}}
    <!-- Header content -->
{{/if}}

Calculated Values

Pre-calculate values in C# and pass them to templates:

var items = new[]
{
    new { description = "Item 1", quantity = 5, price = 10.00 },
    new { description = "Item 2", quantity = 3, price = 15.00 },
    new { description = "Item 3", quantity = 2, price = 20.00 }
};

// Calculate totals
var subtotal = items.Sum(i => i.quantity * i.price);
var tax = subtotal * 0.08m;
var total = subtotal + tax;

doc.Params["model"] = new
{
    items = items,
    subtotal = subtotal,
    tax = tax,
    total = total,
    taxRate = 0.08,
    itemCount = items.Length
};

Template:

<p>Items: {{model.itemCount}}</p>
<p>Subtotal: ${{format(model.subtotal, 'F2')}}</p>
<p>Tax ({{format(model.taxRate, 'P0')}}): ${{format(model.tax, 'F2')}}</p>
<p><strong>Total: ${{format(model.total, 'F2')}}</strong></p>

Why calculate in C#?

  • More reliable than template calculations
  • Better performance
  • Easier to unit test
  • Type-safe calculations
  • Access to full .NET capabilities

Parameter Scope

Global Parameters

Parameters set via doc.Params are available throughout the entire document:

doc.Params["companyName"] = "Tech Corp";
doc.Params["year"] = 2025;
<!-- Available in header -->
<div class="header">
    <h1>{{companyName}}</h1>
</div>

<!-- Available in body -->
<div class="content">
    <p>Copyright {{year}} {{companyName}}</p>
</div>

<!-- Available in footer -->
<div class="footer">
    <p>{{companyName}} - {{year}}</p>
</div>

Common Patterns

Pattern 1: Separating Data and Metadata

// Content data
doc.Params["data"] = actualData;

// Metadata
doc.Params["meta"] = new
{
    generatedDate = DateTime.Now,
    generatedBy = currentUser.Name,
    version = "1.0",
    documentType = "Invoice"
};

// Configuration
doc.Params["config"] = new
{
    showWatermark = false,
    includePageNumbers = true,
    colorScheme = "blue"
};

Pattern 2: Passing Helper Values

doc.Params["model"] = invoiceData;

// Helper values for calculations and formatting
doc.Params["helpers"] = new
{
    currentDate = DateTime.Now,
    currencySymbol = "$",
    dateFormat = "MMMM dd, yyyy",
    numberFormat = "F2",
    taxRate = 0.08
};

Template:

<p>Generated: {{format(helpers.currentDate, helpers.dateFormat)}}</p>
<p>Tax Rate: {{format(helpers.taxRate, 'P0')}}</p>
<p>Total: {{helpers.currencySymbol}}{{format(model.total, helpers.numberFormat)}}</p>

Pattern 3: Conditional Configuration

var reportType = "detailed"; // or "summary"

doc.Params["model"] = reportData;
doc.Params["config"] = new
{
    reportType = reportType,
    showDetails = reportType == "detailed",
    showCharts = reportType == "detailed",
    showSummaryOnly = reportType == "summary"
};

Template:

<h1>{{model.title}}</h1>

{{#if config.showSummaryOnly}}
    <div class="summary">
        <p>{{model.summary}}</p>
    </div>
{{/if}}

{{#if config.showDetails}}
    <div class="details">
        <h2>Detailed Analysis</h2>
        <!-- Detailed content -->
    </div>
{{/if}}

{{#if config.showCharts}}
    <div class="charts">
        <!-- Chart content -->
    </div>
{{/if}}

Practical Examples

Example 1: Multi-Section Report with Shared Data

C# Code:

var doc = Document.ParseDocument("report.html");

// Global company info
doc.Params["company"] = new
{
    name = "Tech Corp",
    logo = "./images/logo.png",
    address = "123 Main St, Springfield, IL",
    phone = "555-1234",
    email = "info@techcorp.com"
};

// Report metadata
doc.Params["report"] = new
{
    title = "Annual Financial Report",
    year = 2024,
    preparedBy = "Finance Department",
    preparedDate = DateTime.Now,
    confidential = true
};

// Financial data
doc.Params["financials"] = new
{
    revenue = 5000000,
    expenses = 3500000,
    profit = 1500000,
    profitMargin = 0.30,
    yearOverYearGrowth = 0.15
};

// Quarterly breakdown
doc.Params["quarters"] = new[]
{
    new { quarter = "Q1", revenue = 1100000, expenses = 850000 },
    new { quarter = "Q2", revenue = 1200000, expenses = 900000 },
    new { quarter = "Q3", revenue = 1300000, expenses = 875000 },
    new { quarter = "Q4", revenue = 1400000, expenses = 875000 }
};

doc.SaveAsPDF("annual-report.pdf");

Template:

<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml'>
<head>
    <title>{{report.title}}</title>
    <style>
        @page {
            size: Letter;
            margin: 1in;
            @top-center {
                content: "{{company.name}} - {{report.year}}";
                font-size: 9pt;
                color: #666;
            }
            @bottom-center {
                content: "Page " counter(page) " of " counter(pages);
                font-size: 9pt;
                color: #666;
            }
        }
        body {
            font-family: Helvetica, sans-serif;
        }
        h1 {
            color: #1e40af;
            border-bottom: 3pt solid #1e40af;
            padding-bottom: 10pt;
        }
        .confidential {
            background-color: #fee2e2;
            color: #991b1b;
            padding: 10pt;
            border: 2pt solid #dc2626;
            font-weight: bold;
            text-align: center;
            margin-bottom: 20pt;
        }
        .metric-box {
            display: inline-block;
            width: 30%;
            padding: 15pt;
            margin: 10pt 1%;
            border: 2pt solid #2563eb;
            text-align: center;
            border-radius: 5pt;
        }
        .metric-value {
            font-size: 24pt;
            font-weight: bold;
            color: #2563eb;
        }
        .metric-label {
            font-size: 10pt;
            color: #666;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            margin: 20pt 0;
        }
        th {
            background-color: #2563eb;
            color: white;
            padding: 10pt;
            text-align: left;
        }
        td {
            padding: 8pt;
            border-bottom: 1pt solid #e5e7eb;
        }
    </style>
</head>
<body>
    <!-- Header with company info -->
    <div style="text-align: center; margin-bottom: 30pt;">
        <img src="{{company.logo}}" style="height: 60pt;" />
        <h1>{{report.title}}</h1>
        <p style="font-size: 12pt;">{{report.year}}</p>
    </div>

    {{#if report.confidential}}
        <div class="confidential">
            CONFIDENTIAL - Internal Use Only
        </div>
    {{/if}}

    <!-- Report metadata -->
    <p style="font-size: 10pt; color: #666;">
        <strong>Prepared by:</strong> {{report.preparedBy}}<br />
        <strong>Date:</strong> {{format(report.preparedDate, 'MMMM dd, yyyy')}}<br />
        <strong>Company:</strong> {{company.name}}
    </p>

    <!-- Key metrics -->
    <h2>Financial Summary</h2>
    <div>
        <div class="metric-box">
            <div class="metric-value">{{format(financials.revenue, 'C0')}}</div>
            <div class="metric-label">Total Revenue</div>
        </div>
        <div class="metric-box">
            <div class="metric-value">{{format(financials.profit, 'C0')}}</div>
            <div class="metric-label">Net Profit</div>
        </div>
        <div class="metric-box">
            <div class="metric-value">{{format(financials.profitMargin, 'P0')}}</div>
            <div class="metric-label">Profit Margin</div>
        </div>
    </div>

    <!-- Quarterly breakdown -->
    <h2>Quarterly Performance</h2>
    <table>
        <thead>
            <tr>
                <th>Quarter</th>
                <th style="text-align: right;">Revenue</th>
                <th style="text-align: right;">Expenses</th>
                <th style="text-align: right;">Profit</th>
                <th style="text-align: right;">Margin</th>
            </tr>
        </thead>
        <tbody>
            {{#each quarters}}
            <tr>
                <td>{{this.quarter}}</td>
                <td style="text-align: right;">{{format(this.revenue, 'C0')}}</td>
                <td style="text-align: right;">{{format(this.expenses, 'C0')}}</td>
                <td style="text-align: right;">
                    {{format(calc(this.revenue, '-', this.expenses), 'C0')}}
                </td>
                <td style="text-align: right;">
                    {{format(calc(calc(this.revenue, '-', this.expenses), '/', this.revenue), 'P0')}}
                </td>
            </tr>
            {{/each}}
        </tbody>
    </table>

    <!-- Footer with company contact -->
    <div style="margin-top: 50pt; padding-top: 15pt; border-top: 1pt solid #d1d5db; font-size: 9pt; color: #666;">
        <p>
            <strong>{{company.name}}</strong><br />
            {{company.address}}<br />
            Phone: {{company.phone}} | Email: {{company.email}}
        </p>
    </div>
</body>
</html>

Example 2: Reusable Template Components

C# Code:

// Create reusable styling configuration
var brandColors = new
{
    primary = "#2563eb",
    secondary = "#3b82f6",
    success = "#059669",
    warning = "#f59e0b",
    danger = "#dc2626",
    textDark = "#1f2937",
    textLight = "#6b7280",
    backgroundLight = "#f9fafb"
};

var typography = new
{
    fontFamily = "Helvetica, sans-serif",
    h1Size = "24pt",
    h2Size = "20pt",
    h3Size = "16pt",
    bodySize = "11pt",
    smallSize = "9pt"
};

var layout = new
{
    pageSize = "Letter",
    margin = "1in",
    contentWidth = "6.5in",
    sidebarWidth = "2in"
};

doc.Params["brand"] = brandColors;
doc.Params["typography"] = typography;
doc.Params["layout"] = layout;
doc.Params["model"] = actualData;

Template:

<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml'>
<head>
    <title>Document</title>
    <style>
        @page {
            size: {{layout.pageSize}};
            margin: {{layout.margin}};
        }
        body {
            font-family: {{typography.fontFamily}};
            font-size: {{typography.bodySize}};
            color: {{brand.textDark}};
        }
        h1 {
            font-size: {{typography.h1Size}};
            color: {{brand.primary}};
        }
        h2 {
            font-size: {{typography.h2Size}};
            color: {{brand.secondary}};
        }
        h3 {
            font-size: {{typography.h3Size}};
            color: {{brand.textDark}};
        }
        .success {
            color: {{brand.success}};
        }
        .warning {
            color: {{brand.warning}};
        }
        .danger {
            color: {{brand.danger}};
        }
        .muted {
            color: {{brand.textLight}};
        }
    </style>
</head>
<body>
    <h1>{{model.title}}</h1>
    <!-- Content uses brand colors -->
</body>
</html>

Try It Yourself

Exercise 1: Configuration-Driven Template

Create a template that:

  • Accepts a configuration object controlling layout options
  • Shows/hides sections based on config
  • Uses config for styling choices (colors, fonts)
  • Accepts separate data object for content

Exercise 2: Multi-Page Report

Create a report that:

  • Uses global company parameters for header/footer
  • Accepts multiple data parameters (sales, customers, inventory)
  • Calculates summary values in C#
  • Passes formatting preferences as parameters

Exercise 3: Template Factory

Create a C# method that:

  • Accepts different report types
  • Sets appropriate parameters based on type
  • Passes different data based on type
  • Returns generated PDF

Common Pitfalls

❌ Modifying Parameters After Parsing

var doc = Document.ParseDocument("template.html");
doc.SaveAsPDF("output.pdf");
doc.Params["model"] = data; // Too late!

Solution: Set parameters before saving

var doc = Document.ParseDocument("template.html");
doc.Params["model"] = data; // Set first
doc.SaveAsPDF("output.pdf");

❌ Overwriting Parameters

doc.Params["model"] = customerData;
doc.Params["model"] = invoiceData; // Overwrites customer data!

Solution: Use different keys

doc.Params["customer"] = customerData;
doc.Params["invoice"] = invoiceData;

❌ Not Null-Checking Data

doc.Params["model"] = null; // Will cause issues in template

Solution: Validate data

if (data != null)
{
    doc.Params["model"] = data;
}
else
{
    doc.Params["model"] = new { /* default values */ };
}

Next Steps

Now that you understand parameters:

  1. Context & Scope - Master data access in nested contexts
  2. Formatting Output - Format dates, numbers, and text
  3. Advanced Patterns - Complex data binding scenarios

Continue learning → Context & Scope