跳過到頁腳內容
遷移指南

如何從 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 vsIronPDF對比。

範疇 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、Grid)
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 圍繞 render 的 Try/catch

RenderingOptions(PDF 配置)

fo.net (XSL-FO 屬性) IronPDF RenderingOptions
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
text-align text-align 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

After (IronPDF with 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 to PDF 選項,請參閱 IronPDF HTML to 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

After (IronPDF with 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

After (IronPDF - 內建支援):(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 以簡單的 HTML 標頭和頁尾取代複雜的 XSL-FO 區域定義。

範例 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 熱衷於創建直觀且美觀的用戶界面,喜歡使用現代框架並打造結構良好、視覺吸引人的手冊。

除了開發之外,Curtis 對物聯網 (IoT) 有著濃厚的興趣,探索將硬體和軟體結合的創新方式。在閒暇時間,他喜愛遊戲並構建 Discord 機器人,結合科技與創意的樂趣。

鋼鐵支援團隊

我們每週 5 天,每天 24 小時在線上。
聊天
電子郵件
打電話給我