如何从 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:block、fo:table、fo: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。
开始之前
前提条件
- .NET 环境:IronPDF支持 .NET Framework 4.6.2+、.NET Core 3.1+ 和 .NET 5/6/7/8/9+。
- 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"
识别所有 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*"
记录您的 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
步骤 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
第 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"
步骤 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")
完整的 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 |
PaperSize 或 SetCustomPaperSize() |
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
译文(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
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
译文(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
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
后(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
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>
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
}
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
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
性能考虑
重用 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
单元转换助手
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
故障排除
问题 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)
问题 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>
问题 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
}
迁移清单
迁移前
- 对所有 XSL-FO 模板文件进行编目(
.fo,.xslfo) - 文档页面尺寸和边距
- 注意页眉/页脚配置(
fo:static-content) - 确定表格结构和样式
- 将项目备份到版本控制系统
- 获取IronPDF许可证密钥
软件包迁移
- 移除
Fonet或FO.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 相关的代码和实用程序
- 更新文档

