跳至頁尾內容
影片

如何在 C# 中使用自定義日誌記錄

從fo.net(FO.NET)遷移到IronPDF是您.NET PDF生成流程的一次重大升級。 本指南提供了一個簡單的、一步步的過程來轉換您的程式碼庫,從過時的XSL-FO標記遷移到現代的HTML/CSS為基礎的PDF生成,使用您開發團隊已經具備的技能。

為何從fo.net遷移至IronPDF

fo.net的挑戰

fo.net(FO.NET)是早期Apache FOP構建的一個C#移植版本,將XSL-FO文件轉換為PDF。 它採用Apache 2.0授權,但對於當前開發有多項限制:

  1. 過時的技術: XSL-FO(可擴展樣式表語言格式物件)是2001年W3C的一項規範; W3C在2013年關閉了XSL-FO工作組,該語言不再有進一步的開發。

  2. 複雜的學習曲線: XSL-FO需要複雜的基於XML的標記,具有專門的格式化物件(fo:page-sequence等)。

  3. 無HTML/CSS支持: fo.net無法渲染HTML或CSS——您必須自己將HTML轉換為XSL-FO(通常通過XSLT)。

  4. 被遺棄/無人維護: nuget.org上的Fonet包最後發布於2011年4月(v1.0.0,.NET Framework 2.0)。 社區分支Fonet.Standard(.NET Standard 2.0)最後發布於2020年5月(v1.0.5)。 CodePlex庫已經失效,GitHub分支(hahmed/Fo.Net)處於休眠狀態。

  5. 僅限於Windows實際情況: 遺留的System.Drawing(GDI+)API,這有效地將其限制在Windows中。

  6. 現代功能有限: 無JavaScript引擎,無CSS3(flexbox/grid),無現代Web字體載入。

  7. 無URL渲染能力: fo.net無法直接渲染網頁——需要手動將HTML轉換為XSL-FO。

fo.net vs IronPDF比較

方面 fo.net(FO.NET) IronPDF
輸入格式 XSL-FO(過時的XML) HTML/CSS(現代Web標準)
學習曲線 陡峭(XSL-FO專長) 緩和(HTML/CSS知識)
維護性 被遺棄(最後發布於2020年5月) 積極維護
平台支持 僅限於Windows 跨平台(.NET Framework 4.6.2+,.NET Core 3.1+,.NET 5/6/7/8/9+)
CSS支持 None 完全支持CSS3(Flexbox, Grid)
JavaScript None 支援完整 JavaScript
URL渲染 不支持 內建
現代功能 有限 頁眉、頁腳、水印、安全性
文件 過時 詳盡的教程

為何切換是明智之舉

基於XSL-FO的fo.net是在XSL-FO被預期成為文件格式標準時設計的。 但這一預期從未實現。 HTML/CSS成為通用的文件格式,而XSL-FO仍是一門小眾技能——大多數XSL-FO資源來自於2005年至2010年之間,使得維護變得愈發困難。

IronPDF允許您使用已有的技能在現代.NET上建立專業的PDF。


開始之前

前提條件

  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 to 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

RenderingOptions(PDF配置)

fo.net(XSL-FO屬性) IronPDFRenderingOptions
page-height 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 @page規則
<fo:simple-page-master> CSS @page
<fo:page-sequence> <div>
<fo:flow> <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

之前(fo.net與XSL-FO):

// 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

之前(fo.net與XSL-FO):

// 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:頁眉和頁腳

之前(fo.net與XSL-FO):

<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

之後(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

之後(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:

  • 標題:<h6>
  • 段落:<p>
  • 通用容器:<div>
  • 行內文字:<span>

問題3:字體不匹配

問題: 字體看起來與fo.net輸出不同。

解決方案: 使用Web字體或在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模板文件(.xslfo
  • 文件所使用的頁面尺寸和邊距
  • 記錄頁眉/頁腳配置(fo:static-content
  • 識別表格結構和樣式
  • 將專案備份到版本控制
  • 獲得IronPDF授權金鑰

包遷移

  • 移除dotnet remove package Fonet
  • 安裝dotnet add package IronPdf
  • IronPdf
  • 在啟動時設置IronPDF授權金鑰

程式碼遷移

  • FonetDriver.Make()
  • driver.Render()
  • 更新文件輸出從流切換到pdf.SaveAs()
  • 用try/catch來替換錯誤事件處理器
  • HtmlHeaderFooter
  • <fo:page-number/>

測試

  • 比較輸出外觀與原始fo.net PDF
  • 驗證頁面尺寸和邊距
  • 檢查頁眉和頁腳
  • 驗證頁碼
  • 測試表格渲染
  • 驗證圖片載入

遷移後

  • 刪除.xslfo模板文件
  • 移除與fo.net相關的程式碼和工具
  • 更新文件

欲瞭解上述IronPDF功能的更深入討論,請參閱IronPDF API參考

請注意FO.NET、Fonet和Apache FOP是其相關所有者的商標。 本網站未與FO.NET專案或Apache Software Foundation有任何聯繫、認可或贊助。 所有產品名稱、標誌和品牌均為其各自所有者的財產。 比較僅供參考,反映撰寫時公開可用的資訊。

Curtis Chau
技術作家

Curtis Chau擁有Carleton大學的電腦科學學士學位,專精於前端開發,擁有Node.js、TypeScript、JavaScript和React的專業知識。Curtis熱衷於建立直觀且美觀的使用者介面,喜愛使用現代框架並建立結構良好、視覺吸引力的手冊。

除了開發,Curtis對物聯網(IoT)有濃厚的興趣,探索創新的方法來整合硬體和軟體。在空閒時間,他喜歡玩遊戲和建立Discord機器人,結合他對技術的熱愛與創造力。

Iron 支援團隊

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