跳至页脚内容
迁移指南

如何从 fo.net 迁移到 IronPDF for .NET

从fo.net (FO.NET)迁移到IronPDF是 .NET PDF 生成流程的一次重大更新。 本指南提供了一条简单明了的分步路径,帮助您利用开发团队已有的技能,将代码库从过时的 XSL-FO 标记过渡到现代的基于 HTML/CSS 的 PDF 生成。

为什么要从 fo.net 迁移到 IronPDF.

fo.net 的挑战

fo.net 是一个 XSL-FO 到 PDF 的渲染器,但目前的开发存在一些限制:

1.过时的技术: XSL-FO(可扩展样式表语言格式化对象)是 W3C 于 2001 年制定的规范,自 2006 年以来没有更新,因此被普遍认为是过时的。

2.复杂的学习曲线: XSL-FO 需要学习复杂的基于 XML 的标记,以及专门的格式化对象(fo:blockfo:tablefo:page-sequence 等)。

3.不支持 HTML/CSS: fo.net 无法渲染 HTML 或 CSS——需要手动将 HTML 转换为 XSL-FO 标记。

4.已停止维护:原 CodePlex 代码库已失效; GitHub 分叉已停止维护。

5.仅限 Windows: fo.net 对 System.Drawing 有内部依赖关系,这使其无法在 Linux/macOS 上运行。

6.现代功能有限:不支持 JavaScript、CSS3、flexbox/grid、现代网页字体。

7.不支持 URL 渲染: fo.net 无法直接渲染网页——需要手动进行 HTML 到 XSL-FO 的转换。

fo.net 与IronPDF对比。

方面 fo.net (FO.NET) IronPDF
输入格式 XSL-FO(过时的 XML) HTML/CSS(现代网络标准)
学习曲线 Steep (XSL-FO 专业技能) 温柔(HTML/CSS 知识)
维护 无人维护 每月积极维护
平台支持 仅限 Windows 真正的跨平台(.NET 6/7/8/9/10+)
CSS 支持 完整的 CSS3(Flexbox、网格)
JavaScript 完全支持 JavaScript
URL 渲染 不支持 内置
现代功能 有限的 页眉、页脚、水印、安全性
文档 过时 详尽的教程

为什么转换是有意义的

fo.net 是在 XSL-FO 可望成为文档格式化标准时设计的。 这一期望从未实现。 HTML/CSS 已成为通用文档格式,超过 98% 的开发人员了解 HTML/CSS,而了解 XSL-FO 的开发人员不到 1%。 大多数 XSL-FO 资源都是 2005-2010 年的,因此维护难度越来越大。

IronPDF 可让您使用已有的技能创建专业的 PDF,并完全支持现代 .NET 版本,包括 2025 年至 2026 年可用的 .NET 10 和 C# 14。


开始之前

前提条件

  1. .NET 环境:IronPDF支持 .NET Framework 4.6.2+、.NET Core 3.1+ 和 .NET 5/6/7/8/9+。
  2. NuGet 访问权限:确保您可以从 NuGet 安装包。 3.许可证密钥:请从ironpdf.com获取用于生产环境的IronPDF许可证密钥。

备份您的项目

# Create a backup branch
git checkout -b pre-ironpdf-migration
git add .
git commit -m "Backup before fo.net toIronPDFmigration"
# Create a backup branch
git checkout -b pre-ironpdf-migration
git add .
git commit -m "Backup before fo.net toIronPDFmigration"
SHELL

识别所有 fo.net 使用情况

# Find all fo.net references
grep -r "FonetDriver\|Fonet\|\.fo\"\|xsl-region" --include="*.cs" --include="*.csproj" .

# Find all XSL-FO template files
find . -name "*.fo" -o -name "*.xslfo" -o -name "*xsl-fo*"
# Find all fo.net references
grep -r "FonetDriver\|Fonet\|\.fo\"\|xsl-region" --include="*.cs" --include="*.csproj" .

# Find all XSL-FO template files
find . -name "*.fo" -o -name "*.xslfo" -o -name "*xsl-fo*"
SHELL

记录您的 XSL-FO 模板

在迁移之前,将所有 XSL-FO 文件编目并注明:

  • 页面尺寸和页边距
  • 使用的字体
  • 表格及其结构
  • 页眉和页脚(fo:static-content
  • 页码模式
  • 图像引用

快速启动迁移

步骤 1:更新 NuGet 软件包

# Remove fo.net package
dotnet remove package Fonet
dotnet remove package FO.NET

# Install IronPDF
dotnet add package IronPdf
# Remove fo.net package
dotnet remove package Fonet
dotnet remove package FO.NET

# Install IronPDF
dotnet add package IronPdf
SHELL

步骤 2:更新命名空间

// Before (fo.net)
using Fonet;
using Fonet.Render.Pdf;
using System.Xml;

// After (IronPDF)
using IronPdf;
using IronPdf.Rendering;
// Before (fo.net)
using Fonet;
using Fonet.Render.Pdf;
using System.Xml;

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

第 3 步:初始化 IronPDF.

// Set license key at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Set license key at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
' Set license key at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

步骤 4:基本转换模式

// Before (fo.net with XSL-FO)
FonetDriver driver = FonetDriver.Make();
using (FileStream output = new FileStream("output.pdf", FileMode.Create))
{
    driver.Render(new StringReader(xslFoContent), output);
}

// After (IronPDF with HTML)
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("output.pdf");
// Before (fo.net with XSL-FO)
FonetDriver driver = FonetDriver.Make();
using (FileStream output = new FileStream("output.pdf", FileMode.Create))
{
    driver.Render(new StringReader(xslFoContent), output);
}

// After (IronPDF with HTML)
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("output.pdf");
Imports System.IO
Imports Fonet
Imports IronPdf

' Before (fo.net with XSL-FO)
Dim driver As FonetDriver = FonetDriver.Make()
Using output As FileStream = New FileStream("output.pdf", FileMode.Create)
    driver.Render(New StringReader(xslFoContent), output)
End Using

' After (IronPDF with HTML)
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs("output.pdf")
$vbLabelText   $csharpLabel

完整的 API 参考

命名空间映射

fo.net 命名空间 IronPDF 同等产品
Fonet IronPdf
Fonet.Render.Pdf IronPdf
Fonet.Layout 不适用
Fonet.Fo 不适用
Fonet.Image IronPdf

FonetDriver 到 ChromePdfRenderer。

FonetDriver 方法 IronPDF 同等产品
FonetDriver.Make() new ChromePdfRenderer()
driver.Render(inputStream, outputStream) renderer.RenderHtmlAsPdf(html)
driver.Render(inputFile, outputStream) renderer.RenderHtmlFileAsPdf(path)
driver.BaseDirectory RenderingOptions.BaseUrl
driver.OnError += handler 围绕渲染的 Try/catch

渲染选项(PDF 配置)

fo.net(XSL-FO 属性) IronPDF 渲染选项
page-height PaperSizeSetCustomPaperSize()
page-width PaperSize
margin-top MarginTop
margin-bottom MarginBottom
margin-left MarginLeft
margin-right MarginRight
reference-orientation PaperOrientation

XSL-FO 到 HTML 转换指南

将 XSL-FO 元素转换为 HTML/CSS.

这次 fo.net 迁移的基本转变是将 XSL-FO 元素转换为 HTML 对应元素:

XSL-FO 元素 HTML/CSS 同等内容
<fo:root> <html>
<fo:layout-master-set> CSS 规则
<fo:simple-page-master> CSS @page
<fo:page-sequence> <body><div>
<fo:flow> <main><div>
<fo:static-content> HtmlHeaderFooter
<fo:block> <p>, <div>, <h1>-<h6>
<fo:inline> <span>
<fo:table> <table>
<fo:table-row> <tr>
<fo:table-cell> <td>, <th>
<fo:list-block> <ul>, <ol>
<fo:list-item> <li>
<fo:external-graphic> <img>
<fo:page-number> {page}占位符
<fo:page-number-citation> {total-pages}
<fo:basic-link> <a href>

将 XSL-FO 属性转换为 CSS.

XSL-FO 属性 等效 CSS 范例
font-family font-family 相同语法
font-size font-size 相同语法
font-weight font-weight bold, normal, 700
@@--CODE-3910--@ @@--CODE-3910--@ left, center, right, justify
color color 十六进制、RGB、名称
background-color background-color 相同语法
space-before margin-top 元素前
space-after margin-bottom 要素之后
start-indent margin-left 左缩进
keep-together page-break-inside: avoid 防止断句
break-before="page" page-break-before: always 强制分页

代码示例

示例 1:将基本 HTML 转换为 PDF.

之前(使用 XSL-FO 的 fo.net):

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

class Program
{
    static void Main()
    {
        // fo.net 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()
    {
        // fo.net 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));
    }
}
Imports Fonet
Imports Fonet.Render.Pdf
Imports System.IO
Imports System.Xml

Module Program
    Sub Main()
        ' fo.net requires XSL-FO format, not HTML
        ' First convert HTML to XSL-FO (manual process)
        Dim xslFo As String = "<?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>"

        Dim driver As FonetDriver = FonetDriver.Make()
        driver.Render(New StringReader(xslFo), 
            New FileStream("output.pdf", FileMode.Create))
    End Sub
End Module
$vbLabelText   $csharpLabel

译文(IronPDF 与 HTML):

// 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");
    }
}
Imports IronPdf

Class Program
    Shared Sub Main()
        Dim renderer = New ChromePdfRenderer()
        Dim html As String = "<h1>Hello World</h1><p>This is HTML content.</p>"
        Dim pdf = renderer.RenderHtmlAsPdf(html)
        pdf.SaveAs("output.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

IronPDF 方法将 25 行以上的 XSL-FO 标记减少到仅 4 行简洁的 C# 代码。 有关 HTML 转 PDF 的更多选项,请参阅 IronPDF HTML 转 PDF 文档

示例 2:带有自定义设置的 PDF 文件

之前(使用 XSL-FO 的 fo.net):

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

class Program
{
    static void Main()
    {
        // fo.net 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()
    {
        // fo.net 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));
    }
}
Imports Fonet
Imports Fonet.Render.Pdf
Imports System.IO

Class Program
    Shared Sub Main()
        ' fo.net settings are configured in XSL-FO markup
        Dim xslFo As String = "<?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>"

        Dim driver As FonetDriver = FonetDriver.Make()
        driver.Render(New StringReader(xslFo), 
            New FileStream("custom.pdf", FileMode.Create))
    End Sub
End Class
$vbLabelText   $csharpLabel

译文(IronPDF 与 HTML):

// 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");
    }
}
Imports IronPdf
Imports IronPdf.Engines.Chrome

Class Program
    Shared Sub Main()
        Dim renderer As New ChromePdfRenderer()
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
        renderer.RenderingOptions.MarginTop = 20
        renderer.RenderingOptions.MarginBottom = 20
        renderer.RenderingOptions.MarginLeft = 25
        renderer.RenderingOptions.MarginRight = 25

        Dim html As String = "<h1 style='font-size:14pt'>Custom PDF</h1>"
        Dim pdf = renderer.RenderHtmlAsPdf(html)
        pdf.SaveAs("custom.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

IronPDF 提供编程式渲染选项,而不是在 XML 标记中嵌入配置。

示例 3:URL 转 PDF.

之前(不支持 fo.net):

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

class Program
{
    static void Main()
    {
        // fo.net 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 - extremely complex
        throw new System.NotImplementedException();
    }
}
// NuGet: Install-Package Fonet
using Fonet;
using System.IO;
using System.Net;

class Program
{
    static void Main()
    {
        // fo.net 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 - extremely complex
        throw new System.NotImplementedException();
    }
}
Imports Fonet
Imports System.IO
Imports System.Net

Class Program
    Shared Sub Main()
        ' fo.net does not support URL rendering directly
        ' Must manually download, convert HTML to XSL-FO, then render
        Dim url As String = "https://example.com"
        Dim html As String = New WebClient().DownloadString(url)

        ' Manual conversion from HTML to XSL-FO required (complex)
        Dim xslFo As String = ConvertHtmlToXslFo(html) ' Not built-in

        Dim driver As FonetDriver = FonetDriver.Make()
        driver.Render(New StringReader(xslFo), 
                      New FileStream("webpage.pdf", FileMode.Create))
    End Sub

    Shared Function ConvertHtmlToXslFo(html As String) As String
        ' Custom implementation required - extremely complex
        Throw New System.NotImplementedException()
    End Function
End Class
$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");
    }
}
Imports IronPdf

Class Program
    Shared Sub Main()
        Dim renderer = New ChromePdfRenderer()
        Dim pdf = renderer.RenderUrlAsPdf("https://example.com")
        pdf.SaveAs("webpage.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

URL 到 PDF 的渲染是此次 fo.net 迁移的最大优势之一。IronPDF可通过完整的JavaScript执行来处理这些问题。 了解有关 URL 至 PDF 转换的更多信息。

示例 4:页眉和页脚

之前(使用 XSL-FO 的 fo.net):

<fo:static-content flow-name="xsl-region-before">
    <fo:block text-align="center" font-size="10pt">
        Company Name - Confidential
    </fo:block>
</fo:static-content>

<fo:static-content flow-name="xsl-region-after">
    <fo:block text-align="right" font-size="10pt">
        Page <fo:page-number/> of <fo:page-number-citation ref-id="last-page"/>
    </fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-before">
    <fo:block text-align="center" font-size="10pt">
        Company Name - Confidential
    </fo:block>
</fo:static-content>

<fo:static-content flow-name="xsl-region-after">
    <fo:block text-align="right" font-size="10pt">
        Page <fo:page-number/> of <fo:page-number-citation ref-id="last-page"/>
    </fo:block>
</fo:static-content>
XML

After (IronPDF):

renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter()
{
    HtmlFragment = "<div style='text-align:center; font-size:10pt;'>Company Name - Confidential</div>",
    DrawDividerLine = true
};

renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter()
{
    HtmlFragment = "<div style='text-align:right; font-size:10pt;'>Page {page} of {total-pages}</div>",
    DrawDividerLine = true
};
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter()
{
    HtmlFragment = "<div style='text-align:center; font-size:10pt;'>Company Name - Confidential</div>",
    DrawDividerLine = true
};

renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter()
{
    HtmlFragment = "<div style='text-align:right; font-size:10pt;'>Page {page} of {total-pages}</div>",
    DrawDividerLine = true
};
Imports System

renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter() With {
    .HtmlFragment = "<div style='text-align:center; font-size:10pt;'>Company Name - Confidential</div>",
    .DrawDividerLine = True
}

renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter() With {
    .HtmlFragment = "<div style='text-align:right; font-size:10pt;'>Page {page} of {total-pages}</div>",
    .DrawDividerLine = True
}
$vbLabelText   $csharpLabel

IronPDF 将复杂的 XSL-FO 区域定义替换为简单的 HTML 页眉和页脚

示例 5:PDF 安全性

之前(fo.net):

// fo.net has very limited PDF security options
// Must use post-processing with another library
// fo.net has very limited PDF security options
// Must use post-processing with another library
' fo.net has very limited PDF security options
' Must use post-processing with another library
$vbLabelText   $csharpLabel

After (IronPDF):

using IronPdf;

public byte[] GenerateSecurePdf(string html)
{
    var renderer = new ChromePdfRenderer();
    var pdf = renderer.RenderHtmlAsPdf(html);

    // Set metadata
    pdf.MetaData.Title = "Confidential Report";
    pdf.MetaData.Author = "Company Name";

    // Password protection
    pdf.SecuritySettings.OwnerPassword = "owner123";
    pdf.SecuritySettings.UserPassword = "user456";

    // Restrict permissions
    pdf.SecuritySettings.AllowUserCopyPasteContent = false;
    pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.NoPrint;
    pdf.SecuritySettings.AllowUserEdits = IronPdf.Security.PdfEditSecurity.NoEdit;

    return pdf.BinaryData;
}
using IronPdf;

public byte[] GenerateSecurePdf(string html)
{
    var renderer = new ChromePdfRenderer();
    var pdf = renderer.RenderHtmlAsPdf(html);

    // Set metadata
    pdf.MetaData.Title = "Confidential Report";
    pdf.MetaData.Author = "Company Name";

    // Password protection
    pdf.SecuritySettings.OwnerPassword = "owner123";
    pdf.SecuritySettings.UserPassword = "user456";

    // Restrict permissions
    pdf.SecuritySettings.AllowUserCopyPasteContent = false;
    pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.NoPrint;
    pdf.SecuritySettings.AllowUserEdits = IronPdf.Security.PdfEditSecurity.NoEdit;

    return pdf.BinaryData;
}
Imports IronPdf

Public Function GenerateSecurePdf(html As String) As Byte()
    Dim renderer = New ChromePdfRenderer()
    Dim pdf = renderer.RenderHtmlAsPdf(html)

    ' Set metadata
    pdf.MetaData.Title = "Confidential Report"
    pdf.MetaData.Author = "Company Name"

    ' Password protection
    pdf.SecuritySettings.OwnerPassword = "owner123"
    pdf.SecuritySettings.UserPassword = "user456"

    ' Restrict permissions
    pdf.SecuritySettings.AllowUserCopyPasteContent = False
    pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.NoPrint
    pdf.SecuritySettings.AllowUserEdits = IronPdf.Security.PdfEditSecurity.NoEdit

    Return pdf.BinaryData
End Function
$vbLabelText   $csharpLabel

性能考虑

重用 ChromePdfRenderer。

为了在 fo.net 迁移期间获得最佳性能,请重用 ChromePdfRenderer 实例:

// GOOD - Reuse the renderer
public class PdfService
{
    private static readonly ChromePdfRenderer _renderer = new ChromePdfRenderer();

    public byte[] Generate(string html) => _renderer.RenderHtmlAsPdf(html).BinaryData;
}

// BAD - Creating new instance each time
public byte[] GenerateBad(string html)
{
    var renderer = new ChromePdfRenderer();  // Wasteful
    return renderer.RenderHtmlAsPdf(html).BinaryData;
}
// GOOD - Reuse the renderer
public class PdfService
{
    private static readonly ChromePdfRenderer _renderer = new ChromePdfRenderer();

    public byte[] Generate(string html) => _renderer.RenderHtmlAsPdf(html).BinaryData;
}

// BAD - Creating new instance each time
public byte[] GenerateBad(string html)
{
    var renderer = new ChromePdfRenderer();  // Wasteful
    return renderer.RenderHtmlAsPdf(html).BinaryData;
}
Imports System

' GOOD - Reuse the renderer
Public Class PdfService
    Private Shared ReadOnly _renderer As New ChromePdfRenderer()

    Public Function Generate(html As String) As Byte()
        Return _renderer.RenderHtmlAsPdf(html).BinaryData
    End Function
End Class

' BAD - Creating new instance each time
Public Function GenerateBad(html As String) As Byte()
    Dim renderer As New ChromePdfRenderer() ' Wasteful
    Return renderer.RenderHtmlAsPdf(html).BinaryData
End Function
$vbLabelText   $csharpLabel

单元转换助手

fo.net XSL-FO 使用多种单位。IronPDF使用毫米作为页边距。 这里有一个辅助类:

public static class UnitConverter
{
    public static double InchesToMm(double inches) => inches * 25.4;
    public static double PointsToMm(double points) => points * 0.352778;
    public static double PicasToMm(double picas) => picas * 4.233;
    public static double CmToMm(double cm) => cm * 10;
}

// Usage
renderer.RenderingOptions.MarginTop = UnitConverter.InchesToMm(1);  // 1 inch
public static class UnitConverter
{
    public static double InchesToMm(double inches) => inches * 25.4;
    public static double PointsToMm(double points) => points * 0.352778;
    public static double PicasToMm(double picas) => picas * 4.233;
    public static double CmToMm(double cm) => cm * 10;
}

// Usage
renderer.RenderingOptions.MarginTop = UnitConverter.InchesToMm(1);  // 1 inch
Public Module UnitConverter
    Public Function InchesToMm(inches As Double) As Double
        Return inches * 25.4
    End Function

    Public Function PointsToMm(points As Double) As Double
        Return points * 0.352778
    End Function

    Public Function PicasToMm(picas As Double) As Double
        Return picas * 4.233
    End Function

    Public Function CmToMm(cm As Double) As Double
        Return cm * 10
    End Function
End Module

' Usage
renderer.RenderingOptions.MarginTop = UnitConverter.InchesToMm(1)  ' 1 inch
$vbLabelText   $csharpLabel

故障排除

问题 1:页面大小差异

问题:迁移到 fo.net 后,PDF 页面大小看起来不一样了。

解决方案:正确映射 XSL-FO 页面尺寸:

// XSL-FO: page-height='11in' page-width='8.5in' (Letter)
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter;

// XSL-FO: page-height='297mm' page-width='210mm' (A4)
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;

// Custom size (in mm)
renderer.RenderingOptions.SetCustomPaperSize(210, 297);
// XSL-FO: page-height='11in' page-width='8.5in' (Letter)
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter;

// XSL-FO: page-height='297mm' page-width='210mm' (A4)
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;

// Custom size (in mm)
renderer.RenderingOptions.SetCustomPaperSize(210, 297);
' XSL-FO: page-height='11in' page-width='8.5in' (Letter)
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter

' XSL-FO: page-height='297mm' page-width='210mm' (A4)
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4

' Custom size (in mm)
renderer.RenderingOptions.SetCustomPaperSize(210, 297)
$vbLabelText   $csharpLabel

问题 2:fo:block 到 HTML 映射

问题:不确定 <fo:block> 应该变成什么。

解决方案:使用合适的语义化 HTML:

  • 标题:<h1><h6>
  • 段落:<p>
  • 通用容器:<div>
  • 内联文本:<span>

问题 3:字体不匹配

问题:字体与 fo.net 输出的字体看起来不一样。

解决方案:使用网页字体或在 CSS 中指定系统字体:

<style>
    @import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
    body { font-family: 'Roboto', Arial, sans-serif; }
</style>
<style>
    @import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
    body { font-family: 'Roboto', Arial, sans-serif; }
</style>
HTML

问题 4:页码不起作用

问题: <fo:page-number/> 不起作用。

解决方案:在页眉/页脚中使用IronPDF占位符:

renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter()
{
    HtmlFragment = "<div style='text-align:center;'>Page {page} of {total-pages}</div>",
    MaxHeight = 15  // mm
};
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter()
{
    HtmlFragment = "<div style='text-align:center;'>Page {page} of {total-pages}</div>",
    MaxHeight = 15  // mm
};
Imports System

renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter() With {
    .HtmlFragment = "<div style='text-align:center;'>Page {page} of {total-pages}</div>",
    .MaxHeight = 15 ' mm
}
$vbLabelText   $csharpLabel

迁移清单

迁移前

  • 对所有 XSL-FO 模板文件进行编目(.fo.xslfo
  • 文档页面尺寸和边距
  • 注意页眉/页脚配置(fo:static-content
  • 确定表格结构和样式
  • 将项目备份到版本控制系统
  • 获取IronPDF许可证密钥

软件包迁移

  • 移除 FonetFO.NET 软件包:dotnet remove package Fonet
  • 安装 IronPdf 软件包:dotnet add package IronPdf
  • 将命名空间导入从 Fonet 更新为 IronPdf
  • 在启动时设置IronPDF许可证密钥

代码迁移

  • FonetDriver.Make() 替换为 new ChromePdfRenderer()
  • driver.Render() 替换为 renderer.RenderHtmlAsPdf()
  • 将流中的文件输出更新为 pdf.SaveAs()
  • 将错误事件处理程序替换为 try/catch
  • fo:static-content 转换为 HtmlHeaderFooter
  • <fo:page-number/> 替换为 {page} 占位符

测试

  • 将输出外观与原始 fo.net PDF 进行比较
  • 检查页面尺寸和边距。
  • 检查页眉和页脚
  • 验证页码
  • 测试表格渲染
  • 验证图像加载情况

后迁移

  • 删除 .fo.xslfo 模板文件
  • 移除与 fo.net 相关的代码和实用程序
  • 更新文档

参考](https://ironpdf.com/object-reference/api/)。

Curtis Chau
技术作家

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

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

钢铁支援团队

我们每周 5 天,每天 24 小时在线。
聊天
电子邮件
打电话给我