比较

FO.NET vs IronPDF for .NET:技术比较指南

当 .NET 开发人员寻找 PDF 生成解决方案时,FO.NET 脱颖而出,成为将 XSL-FO 文档转换为 PDF 的专用工具。 然而,由于它依赖于过时的 XSL-FO 语言、缺乏 HTML/CSS 支持以及已停止维护,许多团队开始考虑替代方案。IronPDF提供了一个使用大多数开发人员已经熟悉的 HTML/CSS 网络标准的现代化解决方案,它采用 Chromium 渲染引擎,并定期每月更新。

本次比较从相关技术方面对这两个库进行了审查,以帮助专业开发人员和架构师根据其 .NET PDF 需求做出明智的决策。

了解 FO.NET.

FO.NET(又称 FoNet)是一个开源库,设计用于使用 C# 将 XSL 格式化对象(XSL-FO)文档转换为 PDF。 该库采用 Apache 2.0 许可证,并将 XSL-FO 语言直接映射到 PDF 格式。

FO.NET 使用 FonetDriver 作为其主要类,通过 Make() 工厂方法创建驱动程序实例,并通过 Render() 方法处理 XSL-FO 输入流以生成 PDF 输出流。 配置在 XSL-FO 标记本身中进行,使用的元素包括 fo:simple-page-masterfo:layout-master-set 以及页边、页面大小和字体的格式属性。

一个显著的局限性在于,FO.NET 需要 XSL-FO 知识——XSL-FO 是一种基于 XML 的语言,是 W3C 于 2001 年制定的规范,自 2006 年以来未进行更新。该库不支持 HTML 或 CSS,也不能直接渲染网页。 在当今的技术领域,XSL-FO 已被普遍认为过时,只有不到 1% 的开发人员精通它,而超过 98% 的开发人员了解 HTML/CSS。

CodePlex 的原始版本库已不复存在,GitHub 的分叉也不再积极维护。 FO.NET 内部依赖 System.Drawing,因此无法在 Linux/macOS 上运行,只能在 Windows 上部署。

了解IronPDF

IronPDF 是一个 .NET PDF 库,它使用 HTML/CSS 进行文档样式和布局,采用开发中常用的 Web 标准。 该库使用 Chromium 渲染引擎,提供完整的 CSS3 支持,包括 Flexbox 和网格布局,以及JavaScript执行。

IronPDF 使用 ChromePdfRenderer 作为其主要的渲染类,RenderingOptions 为页面大小、页边距、页眉、页脚和其他 PDF 设置提供编程配置。 该库支持直接 URL 渲染、HTML 字符串渲染和 HTML 文件渲染,生成的 PdfDocument 对象可以保存、合并、加密或进一步操作。

IronPDF 持续维护,每月发布新版本,支持真正的跨平台部署(Windows、Linux、macOS),并提供详尽的文档和教程。

架构和技术比较

这些 .NET PDF 库的根本区别在于其输入格式和技术基础。

方面FO.NETIronPDF
输入格式XSL-FO(过时的 XML)HTML/CSS(现代网络标准)
学习曲线Steep (XSL-FO 专业技能)温柔(HTML/CSS 知识)
维护放弃每月积极维护
平台支持仅限 Windows真正的跨平台
CSS支持完整的 CSS3(Flexbox、网格)
JavaScript语言完全支持 JavaScript
URL 渲染不支持内置
现代功能有限的页眉、页脚、水印、安全性
文档过时综合教程

设计 FO.NET 时,XSL-FO 正有望成为文档格式化的标准。 但这种情况并没有发生--TML/CSS 成为了通用文档格式。 大多数 XSL-FO 资源都是 2005-2010 年的,因此越来越难找到最新的信息或社区支持。

代码比较:常见的 PDF 操作

HTML 到 PDF 转换

最基本的操作体现了 XSL-FO 和 HTML 方法之间的模型差异。

FO.NET:

// NuGet: Install-Package Fonet
using Fonet;
using Fonet.Render.Pdf;
using System.IO;
using System.Xml;

class Program
{
    static void Main()
    {
        // FoNet requires XSL-FO format, not HTML
        // First convert HTML to XSL-FO (manual process)
        string xslFo = @"<?xml version='1.0' encoding='utf-8'?>
            <fo:root xmlns:fo='http://www.w3.org/1999/XSL/Format'>
                <fo:layout-master-set>
                    <fo:simple-page-master master-name='page'>
                        <fo:region-body/>
                    </fo:simple-page-master>
                </fo:layout-master-set>
                <fo:page-sequence master-reference='page'>
                    <fo:flow flow-name='xsl-region-body'>
                        <fo:block>Hello World</fo:block>
                    </fo:flow>
                </fo:page-sequence>
            </fo:root>";

        FonetDriver driver = FonetDriver.Make();
        driver.Render(new StringReader(xslFo), 
            new FileStream("output.pdf", FileMode.Create));
    }
}
// NuGet: Install-Package Fonet
using Fonet;
using Fonet.Render.Pdf;
using System.IO;
using System.Xml;

class Program
{
    static void Main()
    {
        // FoNet requires XSL-FO format, not HTML
        // First convert HTML to XSL-FO (manual process)
        string xslFo = @"<?xml version='1.0' encoding='utf-8'?>
            <fo:root xmlns:fo='http://www.w3.org/1999/XSL/Format'>
                <fo:layout-master-set>
                    <fo:simple-page-master master-name='page'>
                        <fo:region-body/>
                    </fo:simple-page-master>
                </fo:layout-master-set>
                <fo:page-sequence master-reference='page'>
                    <fo:flow flow-name='xsl-region-body'>
                        <fo:block>Hello World</fo:block>
                    </fo:flow>
                </fo:page-sequence>
            </fo:root>";

        FonetDriver driver = FonetDriver.Make();
        driver.Render(new StringReader(xslFo), 
            new FileStream("output.pdf", FileMode.Create));
    }
}
$vbLabelText   $csharpLabel

IronPDF:

// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        string html = "<h1>Hello World</h1><p>This is HTML content.</p>";
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("output.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        string html = "<h1>Hello World</h1><p>This is HTML content.</p>";
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("output.pdf");
    }
}
$vbLabelText   $csharpLabel

对比很明显。 FO.NET 要求使用 XML 名称空间声明、fo:rootfo:layout-master-setfo:simple-page-masterfo:page-sequencefo:flowfo:block 元素进行冗长的 XSL-FO 标记,所有这些都是在生成一个简单的 "Hello World "文本之前进行的。 代码注释明确指出"FoNet 需要 XSL-FO 格式,而非 HTML"。

IronPDF 可创建一个渲染器,传递标准 HTML,渲染为 PDF,并使用开发人员已经掌握的语法来保存简单的行。

有关高级 HTML 渲染选项,请浏览 HTML 到 PDF 转换指南

URL到PDF转换

将网页转换为 PDF 显示了一个关键的能力差距。

FO.NET:

// NuGet: Install-Package Fonet
using Fonet;
using System.IO;
using System.Net;

class Program
{
    static void Main()
    {
        // FoNet does not support URL rendering directly
        // Must manually download, convert HTML to XSL-FO, then render
        string url = "https://example.com";
        string html = new WebClient().DownloadString(url);

        // Manual conversion from HTML to XSL-FO required (complex)
        string xslFo = ConvertHtmlToXslFo(html); // Not built-in

        FonetDriver driver = FonetDriver.Make();
        driver.Render(new StringReader(xslFo), 
            new FileStream("webpage.pdf", FileMode.Create));
    }

    static string ConvertHtmlToXslFo(string html)
    {
        // Custom implementation required
        throw new System.NotImplementedException();
    }
}
// NuGet: Install-Package Fonet
using Fonet;
using System.IO;
using System.Net;

class Program
{
    static void Main()
    {
        // FoNet does not support URL rendering directly
        // Must manually download, convert HTML to XSL-FO, then render
        string url = "https://example.com";
        string html = new WebClient().DownloadString(url);

        // Manual conversion from HTML to XSL-FO required (complex)
        string xslFo = ConvertHtmlToXslFo(html); // Not built-in

        FonetDriver driver = FonetDriver.Make();
        driver.Render(new StringReader(xslFo), 
            new FileStream("webpage.pdf", FileMode.Create));
    }

    static string ConvertHtmlToXslFo(string html)
    {
        // Custom implementation required
        throw new System.NotImplementedException();
    }
}
$vbLabelText   $csharpLabel

IronPDF:

// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderUrlAsPdf("https://example.com");
        pdf.SaveAs("webpage.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderUrlAsPdf("https://example.com");
        pdf.SaveAs("webpage.pdf");
    }
}
$vbLabelText   $csharpLabel

FO.NET 明确不支持 URL 呈现。 代码注释指出"FoNet 不支持 URL 直接呈现 "和 "需要手动将 HTML 转换为 XSL-FO(复杂)"。ConvertHtmlToXslFo()方法会抛出NotImplementedException,因为这种转换不是内置的,需要自定义实现。

IronPDF 提供原生 RenderUrlAsPdf() 功能,只需调用一个方法即可处理 URL 获取、JavaScript 执行和渲染,只需三行代码即可完成复杂的未实现工作流。

URL to PDF 文档中了解有关 URL 呈现的更多信息。

具有自定义设置的 PDF 文件

配置页面尺寸和页边距演示了配置方法的差异。

FO.NET:

// NuGet: Install-Package Fonet
using Fonet;
using Fonet.Render.Pdf;
using System.IO;

class Program
{
    static void Main()
    {
        // FoNet settings are configured in XSL-FO markup
        string xslFo = @"<?xml version='1.0' encoding='utf-8'?>
            <fo:root xmlns:fo='http://www.w3.org/1999/XSL/Format'>
                <fo:layout-master-set>
                    <fo:simple-page-master master-name='A4' 
                        page-height='297mm' page-width='210mm'
                        margin-top='20mm' margin-bottom='20mm'
                        margin-left='25mm' margin-right='25mm'>
                        <fo:region-body/>
                    </fo:simple-page-master>
                </fo:layout-master-set>
                <fo:page-sequence master-reference='A4'>
                    <fo:flow flow-name='xsl-region-body'>
                        <fo:block font-size='14pt'>Custom PDF</fo:block>
                    </fo:flow>
                </fo:page-sequence>
            </fo:root>";

        FonetDriver driver = FonetDriver.Make();
        driver.Render(new StringReader(xslFo), 
            new FileStream("custom.pdf", FileMode.Create));
    }
}
// NuGet: Install-Package Fonet
using Fonet;
using Fonet.Render.Pdf;
using System.IO;

class Program
{
    static void Main()
    {
        // FoNet settings are configured in XSL-FO markup
        string xslFo = @"<?xml version='1.0' encoding='utf-8'?>
            <fo:root xmlns:fo='http://www.w3.org/1999/XSL/Format'>
                <fo:layout-master-set>
                    <fo:simple-page-master master-name='A4' 
                        page-height='297mm' page-width='210mm'
                        margin-top='20mm' margin-bottom='20mm'
                        margin-left='25mm' margin-right='25mm'>
                        <fo:region-body/>
                    </fo:simple-page-master>
                </fo:layout-master-set>
                <fo:page-sequence master-reference='A4'>
                    <fo:flow flow-name='xsl-region-body'>
                        <fo:block font-size='14pt'>Custom PDF</fo:block>
                    </fo:flow>
                </fo:page-sequence>
            </fo:root>";

        FonetDriver driver = FonetDriver.Make();
        driver.Render(new StringReader(xslFo), 
            new FileStream("custom.pdf", FileMode.Create));
    }
}
$vbLabelText   $csharpLabel

IronPDF:

// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Engines.Chrome;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
        renderer.RenderingOptions.MarginTop = 20;
        renderer.RenderingOptions.MarginBottom = 20;
        renderer.RenderingOptions.MarginLeft = 25;
        renderer.RenderingOptions.MarginRight = 25;

        string html = "<h1 style='font-size:14pt'>Custom PDF</h1>";
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("custom.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Engines.Chrome;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
        renderer.RenderingOptions.MarginTop = 20;
        renderer.RenderingOptions.MarginBottom = 20;
        renderer.RenderingOptions.MarginLeft = 25;
        renderer.RenderingOptions.MarginRight = 25;

        string html = "<h1 style='font-size:14pt'>Custom PDF</h1>";
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("custom.pdf");
    }
}
$vbLabelText   $csharpLabel

FO.NET 中的代码注释明确指出:"FoNet 设置在 XSL-FO 标记中配置"。页面大小、页边距和格式化作为 fo:simple-page-master 的属性嵌入到 XML 结构中。 这意味着配置与内容要以冗长的 XML 格式交织在一起。

IronPDF 使用编程式 RenderingOptions 属性将配置与内容分开。 PaperSize, MarginTop, MarginBottom, MarginLeft, 和<代码>MarginRight</代码等设置将在呈现器对象上进行设置,而内容则保持纯 HTML 格式。

API 映射参考

对于评估 FO.NET 迁移或比较功能的开发人员,本映射显示了等效操作:

核心类映射

FO.NETIronPDF
<代码>FonetDriver.Make()</代码<代码>new ChromePdfRenderer()</ 代码
<代码>driver.Render(inputStream, outputStream)</代码<代码>renderer.RenderHtmlAsPdf(html)</代码
<代码>driver.Render(inputFile, outputStream)</代码<代码>renderer.RenderHtmlFileAsPdf(path)</代码
<代码>driver.BaseDirectory</代码<代码>RenderingOptions.BaseUrl</代码
<代码>driver.OnError += 处理程序</代码围绕渲染的 Try/catch

XSL-FO 到 RenderingOptions 映射

XSL-FO 属性IronPdf 渲染选项
<代码>页面高度</代码>/<代码>页面宽度</代码<代码>纸张大小</代码
<代码>边框-顶部</代码<代码>页边距</代码
<代码>边距-底部</代码<代码>边距下限</代码
<代码>margin-left</代码<代码>边距左移</代码
<代码>右边距</代码<代码>MarginRight</代码
<代码>参考-导向</代码<代码>文件方向</代码

XSL-FO 元素到 HTML 的映射

XSL-FO 元素HTML 同等内容
<代码></代码<html>
<代码><fo:布局主集></代码CSS @page 规则
<代码></代码CSS @page
<代码></代码<body><div>
<代码><fo:流程></代码<main><div>
<代码><fo:静态内容></代码<代码>HtmlHeaderFooter</代码
<代码><fo:块></代码<p>, <div>, <h1>-<h6>
<代码><fo:表格></代码<table>
<代码></代码<代码>
    </代码>, <代码>
      </代码
<代码><fo:外部图形></代码<img>
<fo:page-number/>{page} 占位符

功能对比摘要

特征FO.NETIronPDF
HTML 至 PDF❌(需要手动 XSL-FO 转换)
URL 至 PDF❌(不支持)
XSL-FO 至 PDF不适用
CSS3 支持✅(Flexbox、Grid)
JavaScript
页眉/页脚XSL-FO 静态内容基于 HTML
页码<代码>fo:页码</代码{page} 占位符
跨平台❌(仅限 Windows)
主动维护❌(已放弃)✅(每月)

当团队考虑从 FO.NET 迁移到IronPDF时。

开发团队评估从 FO.NET 过渡到IronPDF有几个原因:

过时的技术: XSL-FO 是 W3C 于 2001 年制定的规范,自 2006 年以来一直没有更新,已被普遍认为过时。 大多数资源和文档都是 2005-2010 年的,因此越来越难以找到最新信息或聘请具有 XSL-FO 专业知识的开发人员。

学习曲线陡峭: XSL-FO 需要学习复杂的基于 XML 的标记,以及专门的格式化对象( fo:blockfo:tablefo:page-sequence等)。 不到 1% 的开发者了解 XSL-FO,而超过 98% 的开发者了解 HTML/CSS。

不支持 HTML/CSS: FO.NET 无法渲染 HTML 或 CSS——它需要手动将 HTML 转换为 XSL-FO 标记,而该库中没有内置此功能。 拥有网页内容或 HTML 模板的团队必须实施自定义转换逻辑。

已停止维护:原始 CodePlex 存储库已失效,GitHub 分支也不再积极维护。 不开发安全补丁、错误修复和新功能。

平台限制: FO.NET 内部依赖于 System.Drawing,这使其无法在 Linux/macOS 上运行,从而限制了其部署到仅限 Windows 的环境。 现代应用程序越来越需要跨平台部署。

缺少现代功能:不支持 JavaScript,不支持 CSS3 功能(Flexbox、Grid),不支持现代网页字体,也不支持直接 URL 渲染功能。

优势和考虑因素

FO.NET 的优势

-直接 XSL-FO 转换:专门针对 XSL-FO 到 PDF 的转换进行了优化 -开源: Apache 2.0 许可证——可免费使用、修改和分发 -精确控制: XSL-FO 提供对文档布局的精细控制

FO.NET注意事项

-技术已过时: XSL-FO 规范自 2006 年以来未进行任何更新。 -需要具备 XSL-FO 知识:只有不到 1% 的开发人员精通此技术。 -不支持 HTML:无法渲染 HTML 或 CSS 内容 -已弃用:无任何维护或安全更新活动 -仅限 Windows 系统: System.Drawing 依赖项阻止了跨平台使用 -不支持URL渲染:无法直接转换网页 -文档有限:资源已过时

IronPDF的优势

  • HTML/CSS 标准:使用超过 98% 的开发人员已经了解的 Web 技术 -现代渲染:采用 Chromium 引擎,完全支持 CSS3 和 JavaScript -积极开发:每月发布新功能和安全补丁 -跨平台:真正支持 Windows、Linux 和 macOS -直接 URL 渲染:原生RenderUrlAsPdf()功能 -专业功能:页眉、页脚、水印、安全功能——全部内置 -丰富的资源:大量的教程文档

IronPDF注意事项

-商业许可:生产用途需要获得许可 -不同的范式: XSL-FO 模板需要转换为 HTML

结论

FO.NET 和IronPDF代表了在 .NET 中生成 PDF 的根本不同方法。 FO.NET 为 XSL-FO 到 PDF 的转换这一利基用例提供了服务,但其对过时技术的依赖、放弃维护、仅限 Windows 系统以及缺乏 HTML 支持等问题使其越来越难以满足新项目的需要。

IronPdf 提供了一种使用 HTML/CSS 网络标准的现代方法,与当前开发人员的技能和技术保持一致。 Chromium 引擎能够直接呈现 HTML、URL 并使用完整的 CSS3,这使得它能够满足现代 PDF 生成的要求。

随着企业对 .NET 10、C# 14 以及 2026 年之前的应用开发进行规划,技术基础至关重要。 维护传统 XSL-FO 系统的团队可以继续使用 FO.NET,但现代 PDF 生成的发展方向显然是基于 HTML 的解决方案,如 IronPDF,这些解决方案可以利用现有的网络开发专业知识。

通过免费试用开始评估 IronPDF,并浏览全面的文档以评估是否适合您的特定需求。