如何在 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.exe 、 wkhtmltox.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 提供面向未來的基礎,並具有積極的開發和現代渲染功能。
開始之前
先決條件
- .NET 環境: .NET Framework 4.6.2+ 或 .NET Core 3.1+ / .NET 5/6/7/8/9+
- NuGet 存取權限:能夠安裝 NuGet 套件
- 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同時從部署環境中移除 wkhtmltopdf 二進位檔案:
- 從專案中刪除
wkhtmltopdf.exe和wkhtmltox.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";識別 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" .完整 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);
}
}(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");
}
}根本區別在於返回類型和保存模式。 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);
}
}(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");
}
}NReco PDF 產生器使用數值尺寸( PageWidth = 210 , PageHeight = 297 )和PageMargins物件。 IronPDF 使用PdfPaperSize列舉(包括 A4、Letter、Legal 等標準尺寸)和RenderingOptions物件上的各個邊距屬性。
關鍵遷移變更:
PageWidth/PageHeight→RenderingOptions.PaperSize = PdfPaperSize.A4new 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);
}
}(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");
}
}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);佔位符語法更新
所有頁首/頁尾佔位符都必須更新:
| 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
};返回類型變更
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;線材安全性和可重複使用性
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;
}非同步支援(新功能)
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;
}故障排除
問題 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();問題 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;問題 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;問題 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
};遷移清單
遷移前
- 清點程式碼庫中所有
NReco.PdfGenerator使用情況 - 記錄所有
CustomWkHtmlArgs和CustomWkHtmlPageArgs的值 列出所有有佔位符的頁首/頁尾HTML模板 - 確定非同步需求(Web 控制器、服務)
- 檢查縮放和邊距設置
- 備份現有 PDF 輸出以進行比較
- 取得 IronPDF 許可證密鑰
軟體包變更
- 移除
NReco.PdfGeneratorNuGet 套件 安裝IronPdfNuGet 套件: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 已移除






