如何在 C# | IronPDF 中新增目錄
wkhtmltopdf 一直是一個廣泛使用的工具,用於利用 Qt 4.8 + QtWebKit 將 HTML 文件轉換為 PDF。 儘管它在開發者中因為其命令行功能和免費授權而廣受歡迎,但該專案現在已產生無法忽視的關鍵安全風險。 GitHub 資源庫已於 2023年1月2日被歸檔; 最後的上游發布版本是 2020年6月11日的 0.12.6; 而 CVE-2022-35583 (CVSS 9.8,SSRF)尚未修補。
本指南提供從 wkhtmltopdf 遷移到IronPDF的完整路徑,為需要消除此安全風險的專業 .NET 開發人員提供逐步指導、程式碼比較和實際範例。
關鍵安全警告:CVE-2022-35583
wkhtmltopdf 包含永遠不會被修補的關鍵安全漏洞:
| 問題 | 詳情 | 狀況 |
|---|---|---|
| CVE-2022-35583 (SSRF, CWE-918) | 危險 (CVSS 9.8) | 未修補 — 維護者有爭議 |
| GitHub 資源庫已歸檔 | 唯讀 | 2023年1月2日 |
| 最後的上游發布 | 0.12.6 | 2020年6月11日 |
| 底層引擎 | Qt 4.8 + QtWebKit (Qt 4.8 在 2015 年結束支援) | 已過時 |
| CSS Grid 支援 | None | 已中斷 |
| Flexbox 支援 | 部分 | 已中斷 |
| ES6+ JavaScript | 有限 | 已中斷 |
SSRF 攻擊的工作原理
伺服器端請求偽造漏洞允許攻擊者存取內部服務、竊取憑據、掃描您的內部網路,並通過精心設計的 HTML 滲透敏感資料:
<iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe>
<img src="http://internal-database:5432/admin"/>
<iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe>
<img src="http://internal-database:5432/admin"/>
當 wkhtmltopdf 渲染此 HTML 時,會從您伺服器的網路上下文中獲取這些 URL,從而繞過防火牆和安全控件。
受影響的封裝程式庫
每個 .NET 封裝都會捆綁或包裹同一個 wkhtmltopdf 本地二進制檔案,因此無論封裝程式庫本身的活動程度如何,它們都會繼承其 CVE 暴露:
| 封裝程式庫 | 最新 NuGet | 安全風險 |
|---|---|---|
| DinkToPdf | 1.0.8 (2017年4月)— 已放棄 | 繼承 CVE-2022-35583 |
| Rotativa.AspNetCore (webgio 分叉) | 1.4.0 (2023年11月)— 封裝更新,二進制凍結 | 繼承 CVE-2022-35583 |
| TuesPechkin | 2.1.1 (2015年1月)— 已放棄 | 繼承 CVE-2022-35583 |
Haukcode.WkHtmlToPdfDotNet (以前是 WkHtmlToPdf-DotNet) |
1.5.95 (2024年10月) — 封裝更新,二進制凍結 | 繼承 CVE-2022-35583 |
| NReco.PdfGenerator | 封裝更新,捆綁 wkhtmltopdf | 繼承 CVE-2022-35583 |
如果您使用了任何這些程式庫,那麼除非您清理所有 HTML 輸入,否則您的應用程式就暴露於 CVE-2022-35583。
IronPDFvs wkhtmltopdf:功能比較
了解結構差異有助於技術決策者評估遷移投資:
| 功能 | wkhtmltopdf | IronPDF |
|---|---|---|
| 授權 | LGPLv3 (免費) | 商業 |
| 渲染引擎 | Qt 4.8 + QtWebKit (Qt 4.8 在 2015 年結束支援) | 當前的 Chromium 引擎 |
| 安全漏洞 | CVE-2022-35583 (CVSS 9.8)未修補,有爭議 | 未報告關鍵 CVE |
| 主動維護 | GitHub 資源庫於 2023年1月2日被歸檔; 最後一次發布是 2020年6月 | 積極維護,定期發布 |
| 對現代 Web 標準的支援 | 有限(Flexbox 已中斷,無 CSS Grid) | 支援 |
| 整合和支援 | 僅限於社區論壇 | 詳盡的文件和專門的支援 |
| CSS Grid CSS 網格布局 | ❌ 不支援 | ✅ 支援 |
| Flexbox | ⚠ 已中斷 | ✅ 支援 |
| ES6+ JavaScript | ❌ 不支援 | ✅ 支援 |
| Async/Await | ❌ 不支援 | ✅ 支援 |
| PDF 操作 | ❌ 不支援 | ✅ 支援 |
| 數位簽名 | ❌ 不支援 | ✅ 支援 |
| PDF/A合規性 | ❌ 不支援 | ✅ 支援 |
快速開始:wkhtmltopdf 遷移到 IronPDF
可以立即透過這些基本步驟開始遷移。
步驟 1:移除 wkhtmltopdf 套件和二進制文件
移除所有 wkhtmltopdf 封裝套件:
# Remove wkhtmltopdf wrapper (whichever you're using)
dotnet remove package Haukcode.WkHtmlToPdfDotNet
dotnet remove package DinkToPdf
dotnet remove package TuesPechkin
dotnet remove package Rotativa
dotnet remove package Rotativa.AspNetCore
dotnet remove package NReco.PdfGenerator
# Remove wkhtmltopdf binary from your deployment
# Delete wkhtmltopdf.exe, wkhtmltox.dll, etc.
# Remove wkhtmltopdf wrapper (whichever you're using)
dotnet remove package Haukcode.WkHtmlToPdfDotNet
dotnet remove package DinkToPdf
dotnet remove package TuesPechkin
dotnet remove package Rotativa
dotnet remove package Rotativa.AspNetCore
dotnet remove package NReco.PdfGenerator
# Remove wkhtmltopdf binary from your deployment
# Delete wkhtmltopdf.exe, wkhtmltox.dll, etc.
步驟 2:安裝 IronPDF
# AddIronPDF(secure, modern alternative)
dotnet add package IronPdf
# AddIronPDF(secure, modern alternative)
dotnet add package IronPdf
步驟 3:更新命名空間
用IronPDF命名空間替換 wkhtmltopdf 命名空間:
// Before (wkhtmltopdf)
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
// After (IronPDF)
using IronPdf;
// Before (wkhtmltopdf)
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
// After (IronPDF)
using IronPdf;
Imports IronPdf
步驟 4:初始化授權
在應用啓動時新增授權初始化:
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
程式碼遷移範例
將HTML轉換為PDF
最基本的操作揭示了這些 .NET PDF 方法之間的複雜性差異。
wkhtmltopdf 方法:
// NuGet: Install-Package Haukcode.WkHtmlToPdfDotNet
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4
},
Objects = {
new ObjectSettings()
{
HtmlContent = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>"
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("output.pdf", pdf);
}
}
// NuGet: Install-Package Haukcode.WkHtmlToPdfDotNet
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4
},
Objects = {
new ObjectSettings()
{
HtmlContent = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>"
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("output.pdf", pdf);
}
}
Imports Haukcode.WkHtmlToPdfDotNet
Imports Haukcode.WkHtmlToPdfDotNet.Contracts
Imports System.IO
Module Program
Sub Main()
Dim converter As New SynchronizedConverter(New PdfTools())
Dim doc As New HtmlToPdfDocument() With {
.GlobalSettings = New GlobalSettings() With {
.ColorMode = ColorMode.Color,
.Orientation = Orientation.Portrait,
.PaperSize = PaperKind.A4
},
.Objects = New List(Of ObjectSettings) From {
New ObjectSettings() With {
.HtmlContent = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>"
}
}
}
Dim pdf As Byte() = converter.Convert(doc)
File.WriteAllBytes("output.pdf", pdf)
End Sub
End Module
IronPDF 方法:
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF from HTML.</p>");
pdf.SaveAs("output.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF from HTML.</p>");
pdf.SaveAs("output.pdf");
}
}
Imports IronPdf
Imports System
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF from HTML.</p>")
pdf.SaveAs("output.pdf")
End Sub
End Class
wkhtmltopdf 需要使用 SynchronizedConverter 建立 PdfTools,使用 GlobalSettings 和 Objects 構建 HtmlToPdfDocument,設置如 ColorMode, Orientation, 和 PaperSize 的屬性,調用 converter.Convert() 以獲取原始字節,並使用 File.WriteAllBytes() 手動寫入文件。
IronPDF 完全消除這一程式—建立 ChromePdfRenderer,調用 RenderHtmlAsPdf(),使用內建的 SaveAs() 方法。
如需進階 HTML 到 PDF 的場景,請參見 HTML 到 PDF 轉換指南。
將 URL 轉換為 PDF
URL到PDF轉換顯示了類似的複雜性模式。
wkhtmltopdf 方法:
// NuGet: Install-Package Haukcode.WkHtmlToPdfDotNet
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4
},
Objects = {
new ObjectSettings()
{
Page = "https://www.example.com"
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("webpage.pdf", pdf);
}
}
// NuGet: Install-Package Haukcode.WkHtmlToPdfDotNet
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4
},
Objects = {
new ObjectSettings()
{
Page = "https://www.example.com"
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("webpage.pdf", pdf);
}
}
Imports Haukcode.WkHtmlToPdfDotNet
Imports Haukcode.WkHtmlToPdfDotNet.Contracts
Imports System.IO
Module Program
Sub Main()
Dim converter As New SynchronizedConverter(New PdfTools())
Dim doc As New HtmlToPdfDocument() With {
.GlobalSettings = New GlobalSettings() With {
.ColorMode = ColorMode.Color,
.Orientation = Orientation.Portrait,
.PaperSize = PaperKind.A4
},
.Objects = New List(Of ObjectSettings) From {
New ObjectSettings() With {
.Page = "https://www.example.com"
}
}
}
Dim pdf As Byte() = converter.Convert(doc)
File.WriteAllBytes("webpage.pdf", pdf)
End Sub
End Module
IronPDF 方法:
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
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;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("webpage.pdf");
}
}
Imports IronPdf
Imports System
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("webpage.pdf")
End Sub
End Class
wkhtmltopdf 在 ObjectSettings 中使用 Page 屬性來指定 URL,需要相同的文件構建模式。IronPDF提供了一個專門的 RenderUrlAsPdf() 方法,清楚地表達意圖。
查看 URL 到 PDF 文件,了解認證和自定義標頭選項。
自訂設定:具有頁面配置的 HTML 文件
配置方向、邊距和紙張尺寸需要不同的方法。
wkhtmltopdf 方法:
// NuGet: Install-Package Haukcode.WkHtmlToPdfDotNet
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Landscape,
PaperSize = PaperKind.A4,
Margins = new MarginSettings() { Top = 10, Bottom = 10, Left = 10, Right = 10 }
},
Objects = {
new ObjectSettings()
{
Page = "input.html",
WebSettings = { DefaultEncoding = "utf-8" }
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("custom-output.pdf", pdf);
}
}
// NuGet: Install-Package Haukcode.WkHtmlToPdfDotNet
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Landscape,
PaperSize = PaperKind.A4,
Margins = new MarginSettings() { Top = 10, Bottom = 10, Left = 10, Right = 10 }
},
Objects = {
new ObjectSettings()
{
Page = "input.html",
WebSettings = { DefaultEncoding = "utf-8" }
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("custom-output.pdf", pdf);
}
}
Imports Haukcode.WkHtmlToPdfDotNet
Imports Haukcode.WkHtmlToPdfDotNet.Contracts
Imports System.IO
Module Program
Sub Main()
Dim converter = New SynchronizedConverter(New PdfTools())
Dim doc = New HtmlToPdfDocument() With {
.GlobalSettings = New GlobalSettings() With {
.ColorMode = ColorMode.Color,
.Orientation = Orientation.Landscape,
.PaperSize = PaperKind.A4,
.Margins = New MarginSettings() With {.Top = 10, .Bottom = 10, .Left = 10, .Right = 10}
},
.Objects = {
New ObjectSettings() With {
.Page = "input.html",
.WebSettings = New WebSettings() With {.DefaultEncoding = "utf-8"}
}
}
}
Dim pdf As Byte() = converter.Convert(doc)
File.WriteAllBytes("custom-output.pdf", pdf)
End Sub
End Module
IronPDF 方法:
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
var pdf = renderer.RenderHtmlFileAsPdf("input.html");
pdf.SaveAs("custom-output.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
var pdf = renderer.RenderHtmlFileAsPdf("input.html");
pdf.SaveAs("custom-output.pdf");
}
}
Imports IronPdf
Imports IronPdf.Rendering
Imports System
Class Program
Shared Sub Main()
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape
renderer.RenderingOptions.MarginTop = 10
renderer.RenderingOptions.MarginBottom = 10
renderer.RenderingOptions.MarginLeft = 10
renderer.RenderingOptions.MarginRight = 10
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
Dim pdf = renderer.RenderHtmlFileAsPdf("input.html")
pdf.SaveAs("custom-output.pdf")
End Sub
End Class
wkhtmltopdf 在 GlobalSettings 和 Objects 中巢狀設置,MarginSettings 作為單獨的物件。IronPDF提供了直接的 RenderingOptions 屬性,具有明確的名稱,如 PaperOrientation, MarginTop, 和 PaperSize。
wkhtmltopdf API 到IronPDF映射參考
此映射透過展示直接的 API 等價加速遷移:
CLI 到IronPDF映射
| wkhtmltopdf CLI 選項 | IronPDF等價 |
|---|---|
wkhtmltopdf input.html output.pdf |
renderer.RenderHtmlFileAsPdf() |
wkhtmltopdf URL output.pdf |
renderer.RenderUrlAsPdf() |
--page-size A4 |
RenderingOptions.PaperSize = PdfPaperSize.A4 |
--page-size Letter |
RenderingOptions.PaperSize = PdfPaperSize.Letter |
--orientation Landscape |
RenderingOptions.PaperOrientation = Landscape |
--margin-top 10mm |
RenderingOptions.MarginTop = 10 |
--margin-bottom 10mm |
RenderingOptions.MarginBottom = 10 |
--margin-left 10mm |
RenderingOptions.MarginLeft = 10 |
--margin-right 10mm |
RenderingOptions.MarginRight = 10 |
--header-html header.html |
RenderingOptions.HtmlHeader |
--footer-center "[page]" |
{page} 佔位符 |
--footer-center "[toPage]" |
{total-pages} 佔位符 |
--enable-javascript |
預設啟用 |
--javascript-delay 500 |
RenderingOptions.WaitFor.RenderDelay = 500 |
--dpi 300 |
RenderingOptions.Dpi = 300 |
--grayscale |
RenderingOptions.GrayScale = true |
C# 封裝 API 映射
| wkhtmltopdf 封裝 | IronPDF |
|---|---|
SynchronizedConverter |
ChromePdfRenderer |
HtmlToPdfDocument |
RenderingOptions |
GlobalSettings.Out |
pdf.SaveAs() |
GlobalSettings.PaperSize |
RenderingOptions.PaperSize |
GlobalSettings.Orientation |
RenderingOptions.PaperOrientation |
GlobalSettings.Margins |
RenderingOptions.Margin* |
ObjectSettings.Page |
RenderHtmlFileAsPdf() |
ObjectSettings.HtmlContent |
RenderHtmlAsPdf() |
converter.Convert(doc) |
renderer.RenderHtmlAsPdf() |
佔位符語法遷移
| wkhtmltopdf 佔位符 | IronPDF 佔位符 |
|---|---|
[page] |
{page} |
[toPage] |
{total-pages} |
[date] |
{date} |
[time] |
{time} |
[title] |
{html-title} |
[url] |
{url} |
常見遷移問題及解決方案
問題 1:頁眉/頁腳佔位符語法
wkhtmltopdf: 使用方括號語法,如 [page] 和 [toPage]。
解決方案: 更新為IronPDF的大括號佔位符:
// Before (wkhtmltopdf)
FooterSettings = { Left = "Page [page] of [toPage]" }
// After (IronPDF)
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div style='text-align:left;'>Page {page} of {total-pages}</div>",
MaxHeight = 25
};
// Before (wkhtmltopdf)
FooterSettings = { Left = "Page [page] of [toPage]" }
// After (IronPDF)
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div style='text-align:left;'>Page {page} of {total-pages}</div>",
MaxHeight = 25
};
' Before (wkhtmltopdf)
FooterSettings = New With {.Left = "Page [page] of [toPage]"}
' After (IronPDF)
renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
.HtmlFragment = "<div style='text-align:left;'>Page {page} of {total-pages}</div>",
.MaxHeight = 25
}
問題 2:JavaScript 延遲配置
wkhtmltopdf: 使用 JavaScriptDelay 屬性,可靠性有限。
解決方案:IronPDF提供多種選擇:
renderer.RenderingOptions.EnableJavaScript = true;
// Option 1: Fixed delay
renderer.RenderingOptions.WaitFor.RenderDelay(500);
// Option 2: Wait for specific element (more reliable)
renderer.RenderingOptions.WaitFor.HtmlElementById("content-loaded");
// Option 3: Wait for JavaScript condition
renderer.RenderingOptions.WaitFor.JavaScript("window.renderComplete === true");
renderer.RenderingOptions.EnableJavaScript = true;
// Option 1: Fixed delay
renderer.RenderingOptions.WaitFor.RenderDelay(500);
// Option 2: Wait for specific element (more reliable)
renderer.RenderingOptions.WaitFor.HtmlElementById("content-loaded");
// Option 3: Wait for JavaScript condition
renderer.RenderingOptions.WaitFor.JavaScript("window.renderComplete === true");
renderer.RenderingOptions.EnableJavaScript = True
' Option 1: Fixed delay
renderer.RenderingOptions.WaitFor.RenderDelay(500)
' Option 2: Wait for specific element (more reliable)
renderer.RenderingOptions.WaitFor.HtmlElementById("content-loaded")
' Option 3: Wait for JavaScript condition
renderer.RenderingOptions.WaitFor.JavaScript("window.renderComplete === true")
問題 3:現代 CSS 無法渲染
症狀: CSS Grid 和 Flexbox 佈局在 wkhtmltopdf 中渲染不正確。
解決方案:IronPDF的 Chromium 引擎正確處理現代 CSS:
// This CSS now works with IronPDF
var html = @"
<style>
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.flex { display: flex; justify-content: space-between; align-items: center; }
</style>
<div class='grid'>
<div>Column 1</div>
<div>Column 2</div>
<div>Column 3</div>
</div>";
var pdf = renderer.RenderHtmlAsPdf(html);
// This CSS now works with IronPDF
var html = @"
<style>
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.flex { display: flex; justify-content: space-between; align-items: center; }
</style>
<div class='grid'>
<div>Column 1</div>
<div>Column 2</div>
<div>Column 3</div>
</div>";
var pdf = renderer.RenderHtmlAsPdf(html);
Dim html As String = "
<style>
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.flex { display: flex; justify-content: space-between; align-items: center; }
</style>
<div class='grid'>
<div>Column 1</div>
<div>Column 2</div>
<div>Column 3</div>
</div>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
問題 4:同步與異步渲染
wkhtmltopdf: 封裝是同步的,並且會阻塞執行緒。
解決方案:IronPDF支援異步渲染:
public async Task<byte[]> GeneratePdfAsync(string html)
{
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(html);
return pdf.BinaryData;
}
public async Task<byte[]> GeneratePdfAsync(string html)
{
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(html);
return pdf.BinaryData;
}
Imports System.Threading.Tasks
Public Async Function GeneratePdfAsync(html As String) As Task(Of Byte())
Dim renderer As New ChromePdfRenderer()
Dim pdf = Await renderer.RenderHtmlAsPdfAsync(html)
Return pdf.BinaryData
End Function
wkhtmltopdf 遷移檢查清單
遷移前任務
審核您的程式碼庫以識別所有 wkhtmltopdf 的使用:
# Find all wkhtmltopdf references
grep -r "Haukcode.WkHtmlToPdfDotNet\|WkHtmlToPdfDotNet\|DinkToPdf\|TuesPechkin\|Rotativa\|NReco.PdfGenerator" --include="*.cs" .
grep -r "wkhtmltopdf" --include="*.yml" --include="*.yaml" --include="Dockerfile" .
# Find all wkhtmltopdf references
grep -r "Haukcode.WkHtmlToPdfDotNet\|WkHtmlToPdfDotNet\|DinkToPdf\|TuesPechkin\|Rotativa\|NReco.PdfGenerator" --include="*.cs" .
grep -r "wkhtmltopdf" --include="*.yml" --include="*.yaml" --include="Dockerfile" .
找到並記錄需要移除的 wkhtmltopdf 二進制文件。 記錄當前設定(紙張尺寸,邊距,頁眉/頁腳)。
程式碼更新任務
- 移除所有 wkhtmltopdf 封裝 NuGet 套件
- 移除 wkhtmltopdf 二進制文件(wkhtmltopdf.exe, wkhtmltox.dll)
- 安裝IronPDFNuGet 套件
- 將命名空間導入從
Haukcode.WkHtmlToPdfDotNet(或您使用的封裝)更新到IronPdf - 將
SynchronizedConverter替換為ChromePdfRenderer - 將
HtmlToPdfDocument模式轉換為直接渲染方法 - 將
GlobalSettings配置更新為RenderingOptions - 將邊距配置從
MarginSettings轉換為單一屬性 - 更新佔位符語法(
[page]→{page},[toPage]→{total-pages}) - 在啟動時新增IronPDF授權初始化
遷移後測試
遷移後,驗證以下方面:
- 視覺比較 PDF 輸出(應改進現代 CSS 支援)
- 驗證現代 CSS 渲染(CSS Grid 和 Flexbox 現在可用)
- 測試帶有大量 JavaScript 的頁面
- 安全掃描確認不再有 wkhtmltopdf 二進制文件
- 負載測試進行性能比較
安全驗證
# Scan for any remaining wkhtmltopdf artifacts
find /var/www/ -name "*wkhtmlto*" 2>/dev/null
find /usr/local/bin/ -name "*wkhtmlto*" 2>/dev/null
docker images | grep wkhtmltopdf
# Check if any process is still using it
ps aux | grep wkhtmltopdf
# Scan for any remaining wkhtmltopdf artifacts
find /var/www/ -name "*wkhtmlto*" 2>/dev/null
find /usr/local/bin/ -name "*wkhtmlto*" 2>/dev/null
docker images | grep wkhtmltopdf
# Check if any process is still using it
ps aux | grep wkhtmltopdf
遷移到IronPDF的關鍵好處
從 wkhtmltopdf 遷移到IronPDF提供了幾個關鍵優勢:
安全: CVE-2022-35583 和所有 wkhtmltopdf 漏洞均被消除。IronPDF沒有已知的 CVE,並定期接收安全更新。
現代渲染引擎:IronPDF使用當前的 Chromium 引擎,確保完整的 CSS3、CSS Grid、Flexbox 和 ES6+ JavaScript 支援。 現代框架會正確渲染。
簡化的 API: 直接渲染方法取代了文件構建模式。 內建的 SaveAs() 方法消除了手動字節處理。
擴展功能: PDF 操作、數位簽名、PDF/A 合規性、水印和合併/分裂操作是 wkhtmltopdf 提供不了的內建功能。
主動開發:IronPDF經常更新以跟進當前的 .NET 版本,因此現代 .NET 和 C# 語言版本會在發佈時提供支援。
異步支援: 本地異步/等待支援可防止高負載網頁應用程式中的執行緒阻塞。

