跳至頁尾內容
移民指南

如何在 C# 中將 NReco PDF 產生器遷移到 IronPDF

為什麼要從 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 框架
JavaScriptES5 基礎完全 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筆記
HtmlToPdfConverterChromePdfRenderer主渲染器
PageMargins個體邊際屬性MarginTop、MarginBottom 等。
PageOrientationPdfPaperOrientation列舉
PageSizePdfPaperSize列舉

渲染方法映射

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 = 210RenderingOptions.PaperSize = PdfPaperSize.A4使用枚舉或 SetCustomPaperSize
PageHeight = 297RenderingOptions.SetCustomPaperSizeinMilimeters(w, h)客製尺寸
Orientation = PageOrientation.LandscapeRenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape景觀
Size = PageSize.A4RenderingOptions.PaperSize = PdfPaperSize.A4紙張尺寸編號

邊緣映射

NReco PDF產生器IronPDF筆記
Margins.Top = 10RenderingOptions.MarginTop = 10單位:毫米
Margins.Bottom = 10RenderingOptions.MarginBottom = 10單位:毫米
Margins.Left = 10RenderingOptions.MarginLeft = 10單位:毫米
Margins.Right = 10RenderingOptions.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 pdfBytesreturn 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擁有卡爾頓大學電腦科學學士學位,專長於前端開發,精通Node.js、TypeScript、JavaScript和React。他熱衷於打造直覺美觀的使用者介面,喜歡使用現代框架,並擅長撰寫結構清晰、視覺效果出色的使用者手冊。

除了開發工作之外,柯蒂斯對物聯網 (IoT) 也抱有濃厚的興趣,致力於探索硬體和軟體整合的創新方法。閒暇時,他喜歡玩遊戲和製作 Discord 機器人,將他對科技的熱愛與創造力結合。