跳過到頁腳內容
MIGRATION GUIDES

How to Migrate from NReco PDF Generator to IronPDF in C#

為什麼要從 NReco PDF 生成器遷移到 IronPDF

NReco PDF產生器有嚴重安全性問題

NReco PDF Generator 對已棄用的 wkhtmltopdf 二進位進行了封裝,繼承了其所有安全漏洞。 這並非理論上的擔憂——自 wkhtmltopdf 於 2020 年停止維護以來,已有 20 多個已記錄在案的 CVE 漏洞沒有可用的修補程式:

  • CVE-2020-21365:伺服器端請求偽造 (SSRF)
  • CVE-2022-35583:透過 HTML 注入讀取本機文件
  • CVE-2022-35580:遠端程式碼執行漏洞

由於底層 wkhtmltopdf 專案已停止維護,因此這些漏洞無法修復。

NReco PDF產生器的其他限制

1.有浮水印的免費版本:生產用途需要付費許可證,定價不透明,需要聯絡銷售人員。

2.已棄用的渲染引擎: WebKit Qt(大約在 2012 年)提供的現代 Web 支援有限:

  • 不使用 CSS Grid 或 Flexbox
  • 不支援現代 JavaScript (ES6+)
  • 網頁字體支援不佳
  • 不使用 CSS 變數或自訂屬性

3.外部二進位依賴項:需要管理每個平台的 wkhtmltopdf 二進位( wkhtmltopdf.exewkhtmltox.dll )。

4.無主動開發:封裝器得到維護,但底層引擎沒有更新。

5.非同步支援有限:同步 API 會阻塞 Web 應用程式中的執行緒。

NReco PDF產生器與IronPDF對比

方面 NReco PDF產生器 IronPDF
渲染引擎 WebKit Qt (2012) 鉻(當前)
安全 超過 20 個 CVE 漏洞,至今沒有修補程式。 主動安全性更新
CSS 支援 CSS2.1,有限的 CSS3 完整的 CSS3、Grid 和 Flexbox 框架
JavaScript ES5 基礎 完全 ES6+,async/await
依賴關係 外部 wkhtmltopdf 二進位文件 自給自足
非同步支援 僅同步 完全異步/等待
網頁字體 有限的 完整的 Google 字體,@font-face
授權 定價不透明,請聯絡銷售人員 透明定價
免費試用 水印 完整功能

對於計劃在 2025 年和 2026 年採用 .NET 10 和 C# 14 的團隊,IronPDF 提供面向未來的基礎,並具有積極的開發和現代渲染功能。


開始之前

先決條件

  1. .NET 環境: .NET Framework 4.6.2+ 或 .NET Core 3.1+ / .NET 5/6/7/8/9+
  2. NuGet 存取權限:能夠安裝 NuGet 套件
  3. IronPDF 許可證:請從ironpdf.com取得您的許可證密鑰。

NuGet 套件變更

# Remove NReco.PdfGenerator
dotnet remove package NReco.PdfGenerator

# Install IronPDF
dotnet add package IronPdf
# Remove NReco.PdfGenerator
dotnet remove package NReco.PdfGenerator

# Install IronPDF
dotnet add package IronPdf
SHELL

同時從部署環境中移除 wkhtmltopdf 二進位檔案

  • 從專案中刪除wkhtmltopdf.exewkhtmltox.dll
  • 刪除所有 wkhtmltopdf 安裝腳本。
  • 刪除平台特定的二進位資料夾

許可證配置

// Add at application startup (Program.cs or Startup.cs)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Add at application startup (Program.cs or Startup.cs)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
$vbLabelText   $csharpLabel

識別 NReco PDF 產生器的使用情況

# Find all NReco.PdfGenerator references
grep -r "NReco.PdfGenerator\|HtmlToPdfConverter\|GeneratePdf" --include="*.cs" .
# Find all NReco.PdfGenerator references
grep -r "NReco.PdfGenerator\|HtmlToPdfConverter\|GeneratePdf" --include="*.cs" .
SHELL

完整 API 參考

核心類別映射

NReco PDF產生器 IronPDF 筆記
HtmlToPdfConverter ChromePdfRenderer 主渲染器
PageMargins 個體邊際屬性 MarginTop、MarginBottom 等。
PageOrientation PdfPaperOrientation 列舉
PageSize PdfPaperSize 列舉

渲染方法映射

NReco PDF產生器 IronPDF 筆記
GeneratePdf(html) RenderHtmlAsPdf(html) 返回 PDF 文檔
GeneratePdfFromFile(url, output) RenderUrlAsPdf(url) 直接 URL 支持
GeneratePdfFromFile(htmlPath, output) RenderHtmlFileAsPdf(path) 文件路徑
(不支援非同步操作) RenderHtmlAsPdfAsync(html) 非同步版本
(不支援非同步操作) RenderUrlAsPdfAsync(url) 非同步版本

頁面配置映射

NReco PDF產生器 IronPDF 筆記
PageWidth = 210 RenderingOptions.PaperSize = PdfPaperSize.A4 使用枚舉或 SetCustomPaperSize
PageHeight = 297 RenderingOptions.SetCustomPaperSizeinMilimeters(w, h) 客製尺寸
Orientation = PageOrientation.Landscape RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape 景觀
Size = PageSize.A4 RenderingOptions.PaperSize = PdfPaperSize.A4 紙張尺寸編號

邊緣映射

NReco PDF產生器 IronPDF 筆記
Margins.Top = 10 RenderingOptions.MarginTop = 10 單位:毫米
Margins.Bottom = 10 RenderingOptions.MarginBottom = 10 單位:毫米
Margins.Left = 10 RenderingOptions.MarginLeft = 10 單位:毫米
Margins.Right = 10 RenderingOptions.MarginRight = 10 單位:毫米
new PageMargins { ... } 個人屬性 無邊距對象

頁首/頁尾佔位符映射

NReco PDF 產生器 (wkhtmltopdf) IronPDF 筆記
[page] {page} 目前頁碼
[topage] {total-pages} 總頁數
[date] {date} 目前日期
[time] {time} 目前時間
[title] {html-title} 文件標題

輸出處理映射

NReco PDF產生器 IronPDF 筆記
byte[] pdfBytes = GeneratePdf(html) PdfDocument pdf = RenderHtmlAsPdf(html) 傳回對象
File.WriteAllBytes(path, bytes) pdf.SaveAs(path) 直接保存
return pdfBytes return pdf.BinaryData 取得位元組數組
new MemoryStream(pdfBytes) pdf.Stream 獲取串流媒體

程式碼遷移範例

範例 1:基本 HTML 轉 PDF

(NReco PDF產生器)之前:

// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;

class Program
{
    static void Main()
    {
        var htmlToPdf = new HtmlToPdfConverter();
        var htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
        var pdfBytes = htmlToPdf.GeneratePdf(htmlContent);
        File.WriteAllBytes("output.pdf", pdfBytes);
    }
}
// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;

class Program
{
    static void Main()
    {
        var htmlToPdf = new HtmlToPdfConverter();
        var htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
        var pdfBytes = htmlToPdf.GeneratePdf(htmlContent);
        File.WriteAllBytes("output.pdf", pdfBytes);
    }
}
$vbLabelText   $csharpLabel

(IronPDF 之後):

// NuGet: Install-Package IronPdf
using IronPdf;
using System.IO;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
        var pdf = renderer.RenderHtmlAsPdf(htmlContent);
        pdf.SaveAs("output.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System.IO;

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

根本區別在於返回類型和保存模式。 NReco PDF產生器 的HtmlToPdfConverter.GeneratePdf()傳回一個byte[] ,您必須使用File.WriteAllBytes()手動將其寫入磁碟。 IronPDF 的ChromePdfRenderer.RenderHtmlAsPdf()傳回一個內建SaveAs()方法的PdfDocument物件。

這種物件導向的方法提供了額外的好處:您可以在儲存之前對 PDF 進行操作(新增浮水印、合併文件、新增安全措施)。 如果您需要原始位元組以與現有程式碼相容,請使用pdf.BinaryData 。 有關其他渲染選項,請參閱HTML 轉 PDF 文件

範例 2:自訂頁面尺寸和邊距

(NReco PDF產生器)之前:

// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;

class Program
{
    static void Main()
    {
        var htmlToPdf = new HtmlToPdfConverter();
        htmlToPdf.PageWidth = 210;
        htmlToPdf.PageHeight = 297;
        htmlToPdf.Margins = new PageMargins { Top = 10, Bottom = 10, Left = 10, Right = 10 };
        var htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>";
        var pdfBytes = htmlToPdf.GeneratePdf(htmlContent);
        File.WriteAllBytes("custom-size.pdf", pdfBytes);
    }
}
// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;

class Program
{
    static void Main()
    {
        var htmlToPdf = new HtmlToPdfConverter();
        htmlToPdf.PageWidth = 210;
        htmlToPdf.PageHeight = 297;
        htmlToPdf.Margins = new PageMargins { Top = 10, Bottom = 10, Left = 10, Right = 10 };
        var htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>";
        var pdfBytes = htmlToPdf.GeneratePdf(htmlContent);
        File.WriteAllBytes("custom-size.pdf", pdfBytes);
    }
}
$vbLabelText   $csharpLabel

(IronPDF 之後):

// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
        renderer.RenderingOptions.MarginTop = 10;
        renderer.RenderingOptions.MarginBottom = 10;
        renderer.RenderingOptions.MarginLeft = 10;
        renderer.RenderingOptions.MarginRight = 10;
        var htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>";
        var pdf = renderer.RenderHtmlAsPdf(htmlContent);
        pdf.SaveAs("custom-size.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
        renderer.RenderingOptions.MarginTop = 10;
        renderer.RenderingOptions.MarginBottom = 10;
        renderer.RenderingOptions.MarginLeft = 10;
        renderer.RenderingOptions.MarginRight = 10;
        var htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>";
        var pdf = renderer.RenderHtmlAsPdf(htmlContent);
        pdf.SaveAs("custom-size.pdf");
    }
}
$vbLabelText   $csharpLabel

NReco PDF 產生器使用數值尺寸( PageWidth = 210PageHeight = 297 )和PageMargins物件。 IronPDF 使用PdfPaperSize列舉(包括 A4、Letter、Legal 等標準尺寸)和RenderingOptions物件上的各個邊距屬性。

關鍵遷移變更:

  • PageWidth / PageHeightRenderingOptions.PaperSize = PdfPaperSize.A4
  • new PageMargins { Top = 10, ... }→ Individual properties:RenderingOptions.MarginTop = 10

對於枚舉未涵蓋的自訂紙張尺寸,請使用RenderingOptions.SetCustomPaperSizeinMilimeters(width, height) 。 了解更多頁面配置選項

範例 3:URL 轉 PDF

(NReco PDF產生器)之前:

// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;

class Program
{
    static void Main()
    {
        var htmlToPdf = new HtmlToPdfConverter();
        var pdfBytes = htmlToPdf.GeneratePdfFromFile("https://www.example.com", null);
        File.WriteAllBytes("webpage.pdf", pdfBytes);
    }
}
// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;

class Program
{
    static void Main()
    {
        var htmlToPdf = new HtmlToPdfConverter();
        var pdfBytes = htmlToPdf.GeneratePdfFromFile("https://www.example.com", null);
        File.WriteAllBytes("webpage.pdf", pdfBytes);
    }
}
$vbLabelText   $csharpLabel

(IronPDF 之後):

// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderUrlAsPdf("https://www.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://www.example.com");
        pdf.SaveAs("webpage.pdf");
    }
}
$vbLabelText   $csharpLabel

NReco PDF Generator 使用名為GeneratePdfFromFile()的方法,該方法既可以處理本地文件,也可以處理 URL,並且第二個參數可以為空。 IronPDF 提供專用方法: RenderUrlAsPdf()用於 URL, RenderHtmlFileAsPdf()用於本機 HTML 檔案。

IronPDF 的方法更簡潔、更直覺。對於非同步 Web 應用程序,請使用await renderer.RenderUrlAsPdfAsync(url)來避免阻塞線程——這是 NReco PDF產生器 所無法做到的。


關鍵遷移說明

縮放價值轉換

NReco PDF 產生器使用浮點數值(0.0-2.0),而 IronPDF 則使用百分比整數:

// NReco PDF Generator: Zoom = 0.9f (90%)
// IronPDF: Zoom = 90

// Conversion formula:
int ironPdfZoom = (int)(nrecoZoom * 100);
// NReco PDF Generator: Zoom = 0.9f (90%)
// IronPDF: Zoom = 90

// Conversion formula:
int ironPdfZoom = (int)(nrecoZoom * 100);
$vbLabelText   $csharpLabel

佔位符語法更新

所有頁首/頁尾佔位符都必須更新:

NReco PDF產生器 IronPDF
[page] {page}
[topage] {total-pages}
[date] {date}
[title] {html-title}
// NReco PDF Generator:
converter.PageFooterHtml = "<div>Page [page] of [topage]</div>";

// IronPDF:
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = "<div>Page {page} of {total-pages}</div>",
    MaxHeight = 20
};
// NReco PDF Generator:
converter.PageFooterHtml = "<div>Page [page] of [topage]</div>";

// IronPDF:
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = "<div>Page {page} of {total-pages}</div>",
    MaxHeight = 20
};
$vbLabelText   $csharpLabel

返回類型變更

NReco PDF 產生器直接回傳byte[] ; IronPDF 返回PdfDocument

// NReco PDF產生器 pattern:
byte[] pdfBytes = converter.GeneratePdf(html);
File.WriteAllBytes("output.pdf", pdfBytes);

// IronPDF pattern:
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");

// Or if you need bytes:
byte[] pdfBytes = renderer.RenderHtmlAsPdf(html).BinaryData;
// NReco PDF產生器 pattern:
byte[] pdfBytes = converter.GeneratePdf(html);
File.WriteAllBytes("output.pdf", pdfBytes);

// IronPDF pattern:
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");

// Or if you need bytes:
byte[] pdfBytes = renderer.RenderHtmlAsPdf(html).BinaryData;
$vbLabelText   $csharpLabel

線材安全性和可重複使用性

NReco PDF Generator 通常每次呼叫都會建立一個新的轉換器。 IronPDF 的ChromePdfRenderer是線程安全的,可以重複使用:

// NReco PDF產生器 pattern (creates new each time):
public byte[] Generate(string html)
{
    var converter = new HtmlToPdfConverter();
    return converter.GeneratePdf(html);
}

// IronPDF pattern (reuse renderer, thread-safe):
private readonly ChromePdfRenderer _renderer = new ChromePdfRenderer();

public byte[] Generate(string html)
{
    return _renderer.RenderHtmlAsPdf(html).BinaryData;
}
// NReco PDF產生器 pattern (creates new each time):
public byte[] Generate(string html)
{
    var converter = new HtmlToPdfConverter();
    return converter.GeneratePdf(html);
}

// IronPDF pattern (reuse renderer, thread-safe):
private readonly ChromePdfRenderer _renderer = new ChromePdfRenderer();

public byte[] Generate(string html)
{
    return _renderer.RenderHtmlAsPdf(html).BinaryData;
}
$vbLabelText   $csharpLabel

非同步支援(新功能)

IronPDF 支援 NReco PDF產生器 無法提供的 async/await 模式:

// NReco PDF Generator: No async support available

// IronPDF: Full async support
public async Task<byte[]> GenerateAsync(string html)
{
    var pdf = await _renderer.RenderHtmlAsPdfAsync(html);
    return pdf.BinaryData;
}
// NReco PDF Generator: No async support available

// IronPDF: Full async support
public async Task<byte[]> GenerateAsync(string html)
{
    var pdf = await _renderer.RenderHtmlAsPdfAsync(html);
    return pdf.BinaryData;
}
$vbLabelText   $csharpLabel

故障排除

問題 1:未找到 HtmlToPdfConverter

問題: IronPDF 中不存在HtmlToPdfConverter類別。

解決方案:使用ChromePdfRenderer

// NReco PDF Generator
var converter = new HtmlToPdfConverter();

// IronPDF
var renderer = new ChromePdfRenderer();
// NReco PDF Generator
var converter = new HtmlToPdfConverter();

// IronPDF
var renderer = new ChromePdfRenderer();
$vbLabelText   $csharpLabel

問題 2:GeneratePdf 回傳錯誤類型

問題:程式碼期望byte[]但得到的是PdfDocument

解決方案:存取.BinaryData屬性:

// NReco PDF Generator
byte[] pdfBytes = converter.GeneratePdf(html);

// IronPDF
byte[] pdfBytes = renderer.RenderHtmlAsPdf(html).BinaryData;
// NReco PDF Generator
byte[] pdfBytes = converter.GeneratePdf(html);

// IronPDF
byte[] pdfBytes = renderer.RenderHtmlAsPdf(html).BinaryData;
$vbLabelText   $csharpLabel

問題 3:未找到 PageMargins 對象

問題: IronPDF 中不存在PageMargins類別。

解決方法:使用單獨的邊距屬性:

// NReco PDF Generator
converter.Margins = new PageMargins { Top = 10, Bottom = 10, Left = 10, Right = 10 };

// IronPDF
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
// NReco PDF Generator
converter.Margins = new PageMargins { Top = 10, Bottom = 10, Left = 10, Right = 10 };

// IronPDF
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
$vbLabelText   $csharpLabel

問題 4:頁碼不顯示

問題: [page][topage]佔位符不起作用。

解決方案:更新 IronPDF 佔位符語法:

// NReco PDF Generator
converter.PageFooterHtml = "<div>Page [page] of [topage]</div>";

// IronPDF
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = "<div>Page {page} of {total-pages}</div>",
    MaxHeight = 20
};
// NReco PDF Generator
converter.PageFooterHtml = "<div>Page [page] of [topage]</div>";

// IronPDF
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = "<div>Page {page} of {total-pages}</div>",
    MaxHeight = 20
};
$vbLabelText   $csharpLabel

遷移清單

遷移前

  • 清點程式碼庫中所有NReco.PdfGenerator使用情況
  • 記錄所有CustomWkHtmlArgsCustomWkHtmlPageArgs的值 列出所有有佔位符的頁首/頁尾HTML模板
  • 確定非同步需求(Web 控制器、服務)
  • 檢查縮放和邊距設置
  • 備份現有 PDF 輸出以進行比較
  • 取得 IronPDF 許可證密鑰

軟體包變更

  • 移除NReco.PdfGenerator NuGet 套件 安裝IronPdf NuGet 套件: dotnet add package IronPdf
  • 將命名空間匯入從using NReco.PdfGenerator;更新為using IronPdf;

程式碼更改

  • 在啟動時新增許可證金鑰配置
  • HtmlToPdfConverter替換為ChromePdfRenderer
  • GeneratePdf(html)替換為RenderHtmlAsPdf(html)
  • GeneratePdfFromFile(url, null)替換為RenderUrlAsPdf(url)
  • PageMargins物件轉換為單獨的邊距屬性
  • 將縮放值從浮點數更新為百分比
  • 更新佔位符語法: [page]{page}[topage]{total-pages}
  • File.WriteAllBytes()替換為pdf.SaveAs()
  • 在有利的情況下,將同步呼叫轉換為非同步呼叫。

移民後

  • 從專案/部署移除 wkhtmltopdf 二進位文件
  • 更新 Docker 檔案以移除 wkhtmltopdf 安裝
  • 執行迴歸測試,比較 PDF 輸出
  • 驗證頁首/頁尾佔位符是否正確渲染。
  • 在所有目標平台(Windows、Linux、macOS)上進行測試
  • 更新 CI/CD 管線,移除 wkhtmltopdf 步驟
  • 更新安全掃描以確認 CVE 已移除

Curtis Chau
技術撰稿人

Curtis Chau 擁有電腦科學學士學位(卡爾頓大學),專長於前端開發,精通 Node.js、TypeScript、JavaScript 和 React。Curtis 對製作直覺且美觀的使用者介面充滿熱情,他喜歡使用現代化的架構,並製作結構良好且視覺上吸引人的手冊。

除了開發之外,Curtis 對物聯網 (IoT) 也有濃厚的興趣,他喜歡探索整合硬體與軟體的創新方式。在空閒時間,他喜歡玩遊戲和建立 Discord bots,將他對技術的熱愛與創意結合。