跳至页脚内容
迁移指南

从 Fluid(模板化)迁移到 IronPdf

Fluid 是一个 .NET 库,它实现了 Liquid 模板语言,为开发人员提供了一种灵活的方式来渲染动态模板,并将内容与表示逻辑分离。 虽然 Fluid 可以有效地生成动态文本输出,但它并不直接支持 PDF 生成——开发人员必须集成额外的 PDF 库才能将 HTML 输出转换为 PDF 文档。 这种双库方法带来了复杂性,而许多开发团队都希望消除这种复杂性。

本指南提供了从使用外部 PDF 库的 Fluid(模板化)到IronPDF的完整迁移路径,为评估这一过渡的 .NET 专业开发人员提供了分步说明、代码比较和实用示例。

为什么要从 Fluid(模板化)迁移到 IronPDF.

Fluid 是一个基于 Liquid 的优秀模板引擎,但将其用于 PDF 生成会引入显著的复杂性:

双库依赖: Fluid 只生成 HTML——你需要一个单独的 PDF 库(wkhtmltopdf、PuppeteerSharp 等)来创建 PDF,这使得你的依赖项和维护负担翻倍。

集成复杂性:协调两个库意味着管理两套配置、错误处理和更新。 当出现故障时,调试变得更具挑战性。

Liquid 语法学习曲线:尽管 C# 已经内置了强大的字符串处理功能,但开发人员仍然必须学习 Liquid 模板语法( {{ }}{% %} )。

PDF 控制有限:您的 PDF 输出质量取决于您选择与 Fluid 搭配使用的 PDF 库,而不是专用的渲染引擎。

调试挑战:模板生成或 PDF 生成阶段都可能出现错误,这使得故障排除比使用单一集成解决方案更加困难。

线程安全问题: TemplateContext不是线程安全的,在并发应用程序中需要谨慎管理。

IronPDFvs Fluid(模板化):功能比较

了解架构差异有助于技术决策者评估迁移投资:

方面流体 + PDF 库IronPDF
依赖关系2 个以上软件包(Fluid + PDF 库)单个软件包
模板液体语法({{ }}</code)C# 字符串插值或 Razor
PDF 生成需要外部库内置 Chromium 引擎
CSS支持取决于 PDF 库带有 Flexbox/Grid 的完整 CSS3
JavaScript语言取决于 PDF 库完全支持 JavaScript
线程安全模板上下文不是线程安全的ChromePdfRenderer 是线程安全的
学习曲线Liquid + PDF 库 APIHTML/CSS(网络标准)
错误处理两个错误源单一错误源

快速入门:从 Fluid 迁移到 IronPDF.

迁移工作可以通过以下基本步骤立即开始。

步骤 1:替换 NuGet 软件包

移除 Fluid 和任何外部 PDF 库:

# Remove Fluid and external PDF library
dotnet remove package Fluid.Core
dotnet remove package WkHtmlToPdf-DotNet  # or whatever PDF library you used
dotnet remove package PuppeteerSharp       # if used
# Remove Fluid and external PDF library
dotnet remove package Fluid.Core
dotnet remove package WkHtmlToPdf-DotNet  # or whatever PDF library you used
dotnet remove package PuppeteerSharp       # if used
SHELL

安装 IronPDF:

# InstallIronPDF(all-in-one solution)
dotnet add package IronPdf
# InstallIronPDF(all-in-one solution)
dotnet add package IronPdf
SHELL

步骤 2:更新命名空间

用 IronPdf 替换 Fluid 命名空间:

// Before (Fluid + external PDF library)
using Fluid;
using Fluid.Values;
using SomeExternalPdfLibrary;

// After (IronPDF)
using IronPdf;
using IronPdf.Rendering;  // For RenderingOptions
// Before (Fluid + external PDF library)
using Fluid;
using Fluid.Values;
using SomeExternalPdfLibrary;

// After (IronPDF)
using IronPdf;
using IronPdf.Rendering;  // For RenderingOptions
$vbLabelText   $csharpLabel

步骤 3:初始化许可证

在应用程序启动时添加许可证初始化:

IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
$vbLabelText   $csharpLabel

代码迁移示例

将基本 HTML 转换为 PDF.

最基本的操作揭示了这些方法之间的关键区别。

流畅的方法:

// NuGet: Install-Package Fluid.Core
using Fluid;
using System.IO;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var parser = new FluidParser();
        var template = parser.Parse("<html><body><h1>Hello {{name}}!</h1></body></html>");
        var context = new TemplateContext();
        context.SetValue("name", "World");
        var html = await template.RenderAsync(context);

        // Fluid only generates HTML - you'd need another library to convert to PDF
        File.WriteAllText("output.html", html);
    }
}
// NuGet: Install-Package Fluid.Core
using Fluid;
using System.IO;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var parser = new FluidParser();
        var template = parser.Parse("<html><body><h1>Hello {{name}}!</h1></body></html>");
        var context = new TemplateContext();
        context.SetValue("name", "World");
        var html = await template.RenderAsync(context);

        // Fluid only generates HTML - you'd need another library to convert to PDF
        File.WriteAllText("output.html", html);
    }
}
$vbLabelText   $csharpLabel

IronPdf 方法:

// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var html = "<html><body><h1>Hello World!</h1></body></html>";
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("output.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var html = "<html><body><h1>Hello World!</h1></body></html>";
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("output.pdf");
    }
}
$vbLabelText   $csharpLabel

Fluid 需要创建一个<代码>FluidParser</代码,解析模板字符串,创建一个<代码>模板上下文</代码,为每个变量调用 SetValue() ,异步渲染以获取 HTML,然后写入文件--这仍然不是 PDF。 代码中的注释明确指出 "Fluid 只能生成 HTML - 您需要另一个库来转换为 PDF"。

IronPDF 消除了这种复杂性:创建一个渲染器,调用 RenderHtmlAsPdf() 并直接保存为 PDF。 无中间 HTML 文件,无附加库。

有关 HTML 转 PDF 的高级应用场景,请参阅 HTML 转 PDF 指南

带动态数据的发票模板

带有多个变量的文档模板可以清楚地显示模板模式的差异。

流畅的方法:

// NuGet: Install-Package Fluid.Core
using Fluid;
using System;
using System.IO;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var parser = new FluidParser();
        var template = parser.Parse(@"
            <html><body>
                <h1>Invoice #{{invoiceNumber}}</h1>
                <p>Date: {{date}}</p>
                <p>Customer: {{customer}}</p>
                <p>Total: ${{total}}</p>
            </body></html>");

        var context = new TemplateContext();
        context.SetValue("invoiceNumber", "12345");
        context.SetValue("date", DateTime.Now.ToShortDateString());
        context.SetValue("customer", "John Doe");
        context.SetValue("total", 599.99);

        var html = await template.RenderAsync(context);
        // Fluid outputs HTML - requires additional PDF library
        File.WriteAllText("invoice.html", html);
    }
}
// NuGet: Install-Package Fluid.Core
using Fluid;
using System;
using System.IO;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var parser = new FluidParser();
        var template = parser.Parse(@"
            <html><body>
                <h1>Invoice #{{invoiceNumber}}</h1>
                <p>Date: {{date}}</p>
                <p>Customer: {{customer}}</p>
                <p>Total: ${{total}}</p>
            </body></html>");

        var context = new TemplateContext();
        context.SetValue("invoiceNumber", "12345");
        context.SetValue("date", DateTime.Now.ToShortDateString());
        context.SetValue("customer", "John Doe");
        context.SetValue("total", 599.99);

        var html = await template.RenderAsync(context);
        // Fluid outputs HTML - requires additional PDF library
        File.WriteAllText("invoice.html", html);
    }
}
$vbLabelText   $csharpLabel

IronPdf 方法:

// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var invoiceNumber = "12345";
        var date = DateTime.Now.ToShortDateString();
        var customer = "John Doe";
        var total = 599.99;

        var html = $@"
            <html><body>
                <h1>Invoice #{invoiceNumber}</h1>
                <p>Date: {date}</p>
                <p>Customer: {customer}</p>
                <p>Total: ${total}</p>
            </body></html>";

        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("invoice.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var invoiceNumber = "12345";
        var date = DateTime.Now.ToShortDateString();
        var customer = "John Doe";
        var total = 599.99;

        var html = $@"
            <html><body>
                <h1>Invoice #{invoiceNumber}</h1>
                <p>Date: {date}</p>
                <p>Customer: {customer}</p>
                <p>Total: ${total}</p>
            </body></html>";

        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("invoice.pdf");
    }
}
$vbLabelText   $csharpLabel

Fluid 使用 Liquid 的 {{variable}} 语法,每个变量使用 context.SetValue() 。 注释中明确指出 "Fluid 输出 HTML - 需要额外的 PDF 库"。IronPDF 使用标准 C# 字符串插值($"{variable}")--开发人员已经熟悉的语法--并直接输出为 PDF。

探索 IronPDF 教程,了解更多文档生成模式。

使用循环的动态数据

带有集合和循环的模板展示了控制流的差异。

流畅的方法:

// NuGet: Install-Package Fluid.Core
using Fluid;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var parser = new FluidParser();
        var template = parser.Parse(@"
            <html><body>
                <h1>{{title}}</h1>
                <ul>
                {% for item in items %}
                    <li>{{item}}</li>
                {% endfor %}
                </ul>
            </body></html>");

        var context = new TemplateContext();
        context.SetValue("title", "My List");
        context.SetValue("items", new[] { "Item 1", "Item 2", "Item 3" });

        var html = await template.RenderAsync(context);
        // Fluid generates HTML only - separate PDF conversion needed
        File.WriteAllText("template-output.html", html);
    }
}
// NuGet: Install-Package Fluid.Core
using Fluid;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var parser = new FluidParser();
        var template = parser.Parse(@"
            <html><body>
                <h1>{{title}}</h1>
                <ul>
                {% for item in items %}
                    <li>{{item}}</li>
                {% endfor %}
                </ul>
            </body></html>");

        var context = new TemplateContext();
        context.SetValue("title", "My List");
        context.SetValue("items", new[] { "Item 1", "Item 2", "Item 3" });

        var html = await template.RenderAsync(context);
        // Fluid generates HTML only - separate PDF conversion needed
        File.WriteAllText("template-output.html", html);
    }
}
$vbLabelText   $csharpLabel

IronPdf 方法:

// NuGet: Install-Package IronPdf
using IronPdf;
using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var title = "My List";
        var items = new[] { "Item 1", "Item 2", "Item 3" };

        var html = $@"
            <html><body>
                <h1>{title}</h1>
                <ul>";

        foreach (var item in items)
        {
            html += $"<li>{item}</li>";
        }

        html += "</ul></body></html>";

        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("template-output.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var title = "My List";
        var items = new[] { "Item 1", "Item 2", "Item 3" };

        var html = $@"
            <html><body>
                <h1>{title}</h1>
                <ul>";

        foreach (var item in items)
        {
            html += $"<li>{item}</li>";
        }

        html += "</ul></body></html>";

        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("template-output.pdf");
    }
}
$vbLabelText   $csharpLabel

Fluid 使用 Liquid 的 {% for item in items %}...{% endfor %} 语法--一种开发人员必须学习的模板语言。 注释指出 "Fluid 仅生成 HTML - 需要单独转换 PDF"。IronPdf 使用标准 C# foreach 循环--无需学习新语法--并直接输出为 PDF。

Fluid API 到IronPDF映射参考

这种映射通过显示直接的 API 对应关系来加速迁移:

核心类映射

流体类IronPdf 同等产品备注
<代码>FluidParser</代码不适用不需要--使用 C# 字符串
<代码>FluidTemplate</代码不适用不需要
<代码>模板上下文</代码C# 对象/字符串直接传递数据
<代码>模板选项</代码<代码>渲染选项</代码PDF 输出配置
<代码>FluidValue</代码本地 C# 类型无需转换
外部 PDF 类<代码>ChromePdfRenderer</代码主渲染类

方法映射

流体方法IronPdf 同等产品备注
<代码>new FluidParser()</ 代码<代码>new ChromePdfRenderer()</ 代码创建呈现器
<代码>parser.Parse(source)</代码不适用不需要-HTML 是一个字符串
<代码>template.RenderAsync(context)</代码<代码>renderer.RenderHtmlAsPdf(html)</代码直接渲染 PDF
<代码>context.SetValue("key", 值)</代码<代码>var key = value;</ 代码使用 C# 变量

Liquid 语法到 C# 的映射

液体语法C# 对等语备注
{{ 变量 }}<代码>$"{变量}"</代码字符串插值
{% for item in items %}<代码>foreach(var item in items)</代码C# 环节
{% if condition %}<代码>if(条件)</代码C# 条件
{{ x \|上例 }}<代码>x.ToUpper()</代码C# 方法
{{ x \|date: '%Y-%m-%d' }}<代码>x.ToString("yyyy-MM-dd")</代码C# 格式化
{{ x \|number_with_precision: 2 }}<代码>x.ToString("F2")</代码C# 数字格式化

常见迁移问题和解决方案

问题 1:液体语法转换

Fluid: 使用 {{ 变量 }}{% 控制 %} 语法。

解决方案:替换为 C# 字符串插值和控制流:

// Liquid: {{ name | upcase }}
// C#: $"{name.ToUpper()}"

// Liquid: {% for item in items %}{{item}}{% endfor %}
// C#: foreach (var item in items) { html += $"{item}"; }
// Liquid: {{ name | upcase }}
// C#: $"{name.ToUpper()}"

// Liquid: {% for item in items %}{{item}}{% endfor %}
// C#: foreach (var item in items) { html += $"{item}"; }
$vbLabelText   $csharpLabel

问题 2:模板上下文变量

Fluid: 使用<代码>context.SetValue("key", 值)</代码来传递数据。

解决方案:使用标准 C# 变量:

// Before (Fluid)
var context = new TemplateContext();
context.SetValue("customer", customerName);

// After (IronPDF)
var customer = customerName;
var html = $"<p>Customer: {customer}</p>";
// Before (Fluid)
var context = new TemplateContext();
context.SetValue("customer", customerName);

// After (IronPDF)
var customer = customerName;
var html = $"<p>Customer: {customer}</p>";
$vbLabelText   $csharpLabel

第 3 期:线程安全

流畅:<代码>模板上下文</代码不是线程安全的,需要在并发应用程序中仔细管理。

解决方案:<代码>ChromePdfRenderer</代码是线程安全的,可以跨线程共享:

// Thread-safe usage
private static readonly ChromePdfRenderer _renderer = new ChromePdfRenderer();

public byte[] GeneratePdf(string html)
{
    var pdf = _renderer.RenderHtmlAsPdf(html);
    return pdf.BinaryData;
}
// Thread-safe usage
private static readonly ChromePdfRenderer _renderer = new ChromePdfRenderer();

public byte[] GeneratePdf(string html)
{
    var pdf = _renderer.RenderHtmlAsPdf(html);
    return pdf.BinaryData;
}
$vbLabelText   $csharpLabel

第 4 期:两阶段错误处理

流畅:错误可能发生在模板阶段或 PDF 生成阶段。

解决方案:IronPDF只有一个错误源:

try
{
    var pdf = renderer.RenderHtmlAsPdf(html);
    pdf.SaveAs("output.pdf");
}
catch (Exception ex)
{
    // Single point of failure—easier debugging
    Console.WriteLine($"PDF generation failed: {ex.Message}");
}
try
{
    var pdf = renderer.RenderHtmlAsPdf(html);
    pdf.SaveAs("output.pdf");
}
catch (Exception ex)
{
    // Single point of failure—easier debugging
    Console.WriteLine($"PDF generation failed: {ex.Message}");
}
$vbLabelText   $csharpLabel

流体迁移核对表

迁移前任务

审核您的代码库,确定所有 Fluid 使用情况:

# Find all Fluid references
grep -r "FluidParser\|FluidTemplate\|TemplateContext\|using Fluid" --include="*.cs" --include="*.csproj" .

# Find Liquid template files
find . -name "*.liquid" -o -name "*.html" | xargs grep -l "{{"
# Find all Fluid references
grep -r "FluidParser\|FluidTemplate\|TemplateContext\|using Fluid" --include="*.cs" --include="*.csproj" .

# Find Liquid template files
find . -name "*.liquid" -o -name "*.html" | xargs grep -l "{{"
SHELL

记录所有模板:文件位置、使用的变量、循环和条件以及外部 PDF 库配置。

代码更新任务

1.删除 Fluid.Core NuGet 软件包 2.删除外部 PDF 库包 3.安装 IronPdf NuGet 软件包 4.更新名称空间导入,从 FluidIronPdf 5.将 {{ 变量 }} 转换为 $"{variable}" 6.将 {% for item in collection %} 转换为 C# foreach 7.将{% if condition %}转换为 C# if 语句 8.将 Liquid 过滤器转换为 C# 方法(例如,...|upcase.ToUpper()) 9.将<代码>FluidParser</代码替换为 ChromePdfRenderer 10.将 TemplateContext.SetValue() 替换为直接 C# 变量 11.删除外部 PDF 库调用 12.在启动时添加 IronPdf 许可证初始化功能

迁移后测试

迁移后,验证这些方面:

  • 验证 PDF 输出是否符合预期
  • 测试所有模板变体是否能正确呈现
  • 检查图像和样式是否正确显示
  • 验证分页符是否正确
  • 使用各种数据大小进行测试
  • 性能测试与 Fluid + 外部库
  • 测试并发场景中的线程安全

清理任务

  • 删除 .liquid 模板文件(如果不再需要)
  • 删除与 Fluid 相关的辅助代码
  • 更新文档
  • 清理未使用的依赖关系

迁移到IronPDF的主要优势

从使用外部 PDF 库的 Fluid(模板化)转向IronPDF具有几个关键优势:

单包解决方案:消除对两个库的依赖。IronPDF在一个软件包中同时处理模板制作(通过 HTML/CSS)和 PDF 生成。

无需学习新语法:使用标准的 C# 字符串插值和控制流,而不是学习 Liquid 模板语法。

线程安全渲染: ChromePdfRenderer是线程安全的,与TemplateContext不同,从而简化了并发 PDF 生成。

Chromium 渲染引擎:行业标准渲染确保完全支持 CSS3,包括 Flexbox 和 Grid,以及完整的 JavaScript 执行。

单一错误源:只需对一个库进行故障排除,而无需在模板和 PDF 生成阶段之间进行协调,从而简化了调试过程。

积极开发:随着 .NET 10 和 C# 14 的普及,IronPDF 将持续更新,确保与当前和未来的 .NET 版本兼容。

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。