CraftMyPDF與IronPDF:技術比較指南
當.NET開發人員查看PDF生成選項時,Haukcode.DinkToPdf作為已停產的DinkToPdf專案的延續而脫穎而出,該專案使用wkhtmltopdf二進位檔。 雖然Haukcode.DinkToPdf提供基本的HTML到PDF轉換,但由於專案已停止,來自wkhtmltopdf的重大安全風險將永遠無法修復。 IronPDF提供不同的選擇:一個積極維護的程式庫,使用現代Chromium引擎,具備定期的安全更新。
這次比較回顧了這兩個程式庫的相關技術方面,以協助開發人員和架構師為其.NET PDF需求做出明智的選擇。
探索Haukcode.DinkToPdf
Haukcode.DinkToPdf是曾經流行的DinkToPdf程式庫的延續,基於現已停產的wkhtmltopdf二進位檔。 該程式庫旨在保持與.NET Core的相容性,同時提供HTML到PDF的轉換。 作為一個已放棄的專案的延續,Haukcode.DinkToPdf存在顯著的局限性。
Haukcode.DinkToPdf使用PdfTools進行轉換。 配置通過包含頁面選項(ColorMode、Orientation、PaperSize、Margins)的GlobalSettings來管理。 byte[]資料。
程式庫需要特定平台的原生二進位檔:libwkhtmltox.dylib(macOS)。 由於wkhtmltopdf的限制,執行緒安全需要在單例模式中使用SynchronizedConverter。
探討IronPDF
IronPDF是一個獨立開發的.NET程式庫,使用現代的Chromium渲染引擎。該程式庫積極維護,定期更新,並具有專業支援和持續的安全修補。
IronPDF使用RenderingOptions屬性進行。 方法如BinaryData存取。 該程式庫是自包含的,不需要外部原生二進位檔,並且從設計上具有執行緒安全,無需單例模式。
重要的安全考量
這些程式庫之間最突出的區別在於安全性。 Haukcode.DinkToPdf繼承了CVE-2022-35583,一個嚴重的伺服器端請求偽造(SSRF)漏洞,CVSS評分為9.8。
CVE-2022-35583攻擊向量:
- 惡意的HTML內容可能使伺服器獲取內部資源
- AWS中繼資料攻擊可存取
http://169.254.169.254竊取憑證 - 內部網路掃描和存取內部服務
- 通過
file://協議進行本地檔案包含 - 潛在的基礎設施完整接管
這個漏洞無法修復,因為wkhtmltopdf已被放棄(自2023年1月存檔,最後版本為2020年的0.12.6)。
| 安全方面 | Haukcode.DinkToPdf | IronPDF |
|---|---|---|
| 重要CVE | CVE-2022-35583(CVSS 9.8,無法修復) | 積極修補 |
| 底層引擎 | wkhtmltopdf(Qt WebKit ~2015) | Chromium(定期更新) |
| 專案狀態 | 放棄專案的分支 | 積極開發 |
| 安全更新 | 預期無更新 | 定期發布 |
| 支持 | 僅限社群 | 專業支持 |
架構與引擎比較
根本的架構差異影響渲染品質、現代網頁標準支持和部署複雜性。
| 方面 | Haukcode.DinkToPdf | IronPDF |
|---|---|---|
| 渲染引擎 | Qt WebKit(~2015) | Chromium(目前) |
| HTML5/CSS3 | 有限 | 支持 |
| JavaScript | 有限,不安全 | 完整的V8引擎 |
| 原生二進位檔 | 必需(平台特定) | 自包含 |
| 執行緒安全性 | 需要單例模式 | 設計中具有執行緒安全性 |
| 更新 | 預期無更新 | 定期發布 |
Haukcode.DinkToPdf依賴於過時的Qt WebKit引擎,意味著缺少多年的安全修補和對現代網頁標準的有限支持。 IronPDF的Chromium引擎提供支持現代網頁標準的能力,並定期更新。
程式碼比較:常見的 PDF 操作
HTML 到 PDF 轉換
最基本的操作展示了API設計的差異。
Haukcode.DinkToPdf:
// NuGet: Install-Package DinkToPdf
using DinkToPdf;
using DinkToPdf.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 = "<html><body><h1>Hello World</h1></body></html>",
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("output.pdf", pdf);
}
}// NuGet: Install-Package DinkToPdf
using DinkToPdf;
using DinkToPdf.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 = "<html><body><h1>Hello World</h1></body></html>",
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("output.pdf", pdf);
}
}Imports DinkToPdf
Imports DinkToPdf.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.Portrait,
.PaperSize = PaperKind.A4
},
.Objects = New List(Of ObjectSettings) From {
New ObjectSettings() With {
.HtmlContent = "<html><body><h1>Hello World</h1></body></html>"
}
}
}
Dim pdf As Byte() = converter.Convert(doc)
File.WriteAllBytes("output.pdf", pdf)
End Sub
End ModuleIronPDF:
// NuGet: Install-Package IronPdf
using IronPdf;
using System.IO;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<html><body><h1>Hello World</h1></body></html>");
pdf.SaveAs("output.pdf");
}
}// NuGet: Install-Package IronPdf
using IronPdf;
using System.IO;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<html><body><h1>Hello World</h1></body></html>");
pdf.SaveAs("output.pdf");
}
}Imports IronPdf
Imports System.IO
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf("<html><body><h1>Hello World</h1></body></html>")
pdf.SaveAs("output.pdf")
End Sub
End ClassHaukcode.DinkToPdf需要建立File.WriteAllBytes()寫入磁碟。
IronPDF建立SaveAs()保存。 使用現代API設計,操作大大更為簡潔。
想了解進階HTML渲染選項,請參閱HTML到PDF轉換指南。
URL到PDF轉換
轉換網頁展示了處理外部內容的不同方法。
Haukcode.DinkToPdf:
// NuGet: Install-Package DinkToPdf
using DinkToPdf;
using DinkToPdf.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 DinkToPdf
using DinkToPdf;
using DinkToPdf.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 DinkToPdf
Imports DinkToPdf.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.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 ModuleIronPDF:
// 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 ClassHaukcode.DinkToPdf使用相同的ObjectSettings.Page屬性指定URL。 IronPDF提供專門的RenderUrlAsPdf()方法,可直接接受URL,這是針對此種使用情況的更簡潔API。
請注意,Haukcode.DinkToPdf的URL渲染存在CVE-2022-35583 SSRF漏洞風險,因為惡意URL或重定向可能會利用伺服器。
自訂頁面設置
頁面配置展示了不同的配置模型。
Haukcode.DinkToPdf:
// NuGet: Install-Package DinkToPdf
using DinkToPdf;
using DinkToPdf.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.Letter,
Margins = new MarginSettings() { Top = 10, Bottom = 10, Left = 10, Right = 10 }
},
Objects = {
new ObjectSettings() {
HtmlContent = "<html><body><h1>Landscape Document</h1><p>Custom page settings</p></body></html>",
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("landscape.pdf", pdf);
}
}// NuGet: Install-Package DinkToPdf
using DinkToPdf;
using DinkToPdf.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.Letter,
Margins = new MarginSettings() { Top = 10, Bottom = 10, Left = 10, Right = 10 }
},
Objects = {
new ObjectSettings() {
HtmlContent = "<html><body><h1>Landscape Document</h1><p>Custom page settings</p></body></html>",
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("landscape.pdf", pdf);
}
}Imports DinkToPdf
Imports DinkToPdf.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.Letter,
.Margins = New MarginSettings() With {.Top = 10, .Bottom = 10, .Left = 10, .Right = 10}
},
.Objects = {
New ObjectSettings() With {
.HtmlContent = "<html><body><h1>Landscape Document</h1><p>Custom page settings</p></body></html>"
}
}
}
Dim pdf As Byte() = converter.Convert(doc)
File.WriteAllBytes("landscape.pdf", pdf)
End Sub
End ModuleIronPDF:
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter;
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
var pdf = renderer.RenderHtmlAsPdf("<html><body><h1>Landscape Document</h1><p>Custom page settings</p></body></html>");
pdf.SaveAs("landscape.pdf");
}
}// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter;
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
var pdf = renderer.RenderHtmlAsPdf("<html><body><h1>Landscape Document</h1><p>Custom page settings</p></body></html>");
pdf.SaveAs("landscape.pdf");
}
}Imports IronPdf
Imports IronPdf.Rendering
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape
renderer.RenderingOptions.MarginTop = 10
renderer.RenderingOptions.MarginBottom = 10
renderer.RenderingOptions.MarginLeft = 10
renderer.RenderingOptions.MarginRight = 10
Dim pdf = renderer.RenderHtmlAsPdf("<html><body><h1>Landscape Document</h1><p>Custom page settings</p></body></html>")
pdf.SaveAs("landscape.pdf")
End Sub
End ClassHaukcode.DinkToPdf透過包含巢狀GlobalSettings來配置頁面設定。 屬性使用類似PaperKind.Letter的枚舉。
IronPDF在渲染器上直接使用RenderingOptions屬性。 屬性單獨設定(PdfPaperOrientation.Landscape)。 兩者對邊距大小使用毫米為單位。
在IronPDF教程中了解有關渲染配置的更多資訊。
API映射參考
評估Haukcode.DinkToPdf遷移或比較功能時,開發人員可以參考此地圖顯示相當操作:
轉換器類別映射
| Haukcode.DinkToPdf | IronPDF |
|---|---|
SynchronizedConverter | ChromePdfRenderer |
BasicConverter | ChromePdfRenderer |
PdfTools | 不適用 |
IConverter | 不適用 |
文件配置映射
| Haukcode.DinkToPdf | IronPDF |
|---|---|
HtmlToPdfDocument | 方法調用 |
GlobalSettings | RenderingOptions |
ObjectSettings | RenderingOptions |
converter.Convert(doc) | renderer.RenderHtmlAsPdf(html) |
全球設定屬性映射
| 全球設定屬性 | IronPDF屬性 |
|---|---|
ColorMode | RenderingOptions.GrayScale |
Orientation | RenderingOptions.PaperOrientation |
PaperSize | RenderingOptions.PaperSize |
Margins.Top | RenderingOptions.MarginTop |
Margins.Bottom | RenderingOptions.MarginBottom |
Margins.Left | RenderingOptions.MarginLeft |
Margins.Right | RenderingOptions.MarginRight |
物件設定屬性映射
| 物件設定屬性 | IronPDF等效 |
|---|---|
HtmlContent | RenderHtmlAsPdf()的第一個參數 |
Page(URL) | renderer.RenderUrlAsPdf(url) |
HeaderSettings.Right = "[page]" | TextHeader.RightText = "{page}" |
佔位符語法差異
標頭/頁尾佔位符在不同程式庫中使用了不同的語法:
| Haukcode.DinkToPdf | IronPDF |
|---|---|
[page] | {page} |
[toPage] | {total-pages} |
[date] | {date} |
執行緒安全和相依性注入
由於從wkhtmltopdf繼承的執行緒安全性限制,Haukcode.DinkToPdf需要仔細處理。
Haukcode.DinkToPdf(需要單例):
// Startup.cs - MUST be singleton due to thread safety issues
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(typeof(IConverter), new SynchronizedConverter(new PdfTools()));
}// Startup.cs - MUST be singleton due to thread safety issues
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(typeof(IConverter), new SynchronizedConverter(new PdfTools()));
}' Startup.vb - MUST be singleton due to thread safety issues
Public Sub ConfigureServices(services As IServiceCollection)
services.AddSingleton(GetType(IConverter), New SynchronizedConverter(New PdfTools()))
End SubIronPDF(靈活):
// Startup.cs - Can be singleton or transient (both work)
public void ConfigureServices(IServiceCollection services)
{
IronPdf.License.LicenseKey = Configuration["IronPdf:LicenseKey"];
services.AddSingleton<IPdfService, IronPdfService>();
// Or services.AddTransient<IPdfService, IronPdfService>() - both are safe!
}// Startup.cs - Can be singleton or transient (both work)
public void ConfigureServices(IServiceCollection services)
{
IronPdf.License.LicenseKey = Configuration["IronPdf:LicenseKey"];
services.AddSingleton<IPdfService, IronPdfService>();
// Or services.AddTransient<IPdfService, IronPdfService>() - both are safe!
}Imports Microsoft.Extensions.DependencyInjection
Public Sub ConfigureServices(services As IServiceCollection)
IronPdf.License.LicenseKey = Configuration("IronPdf:LicenseKey")
services.AddSingleton(Of IPdfService, IronPdfService)()
' Or services.AddTransient(Of IPdfService, IronPdfService) - both are safe!
End SubIronPDF從設計上即具備執行緒安全,允許靈活的相依性注入模式,無需單例要求。
功能比較總結
| 功能 | Haukcode.DinkToPdf | IronPDF |
|---|---|---|
| 來源來源 | 放棄專案的分支 | 獨立開發 |
| 安全 | 繼承自上遊的CVE(不可修復) | 主動修補和安全 |
| 社群和支援 | 小而零星 | 大型、活躍且專注 |
| 功能和更新 | 有限而零星 | 定期和積極開發 |
| 多執行緒支持 | 需要單例模式 | 完全支持和優化 |
| 原生二進位檔 | 必需(平台特定) | 自包含 |
| HTML5/CSS3 | 有限 | 支持 |
| JavaScript | 有限 | 完整的V8引擎 |
| 授權 | MIT(免費) | 商業授權及免費試用 |
當團隊考慮從Haukcode.DinkToPdf轉換到IronPDF時
開發團隊出於多種原因評估從Haukcode.DinkToPdf轉到IronPDF:
重要的安全漏洞: CVE-2022-35583(SSRF)是一個致命漏洞,CVSS 9.8,永遠無法修補。 對於處理使用者提供HTML或呈現外部URL的應用程式,這個漏洞使得AWS憑證盜竊,內部網路存取和本地檔案包含攻擊成為可能。
已廢棄的底層技術: wkhtmltopdf已被放棄(2023年1月已存檔,最後發布為2020年)。 作為一個延續,Haukcode.DinkToPdf無法解決底層技術的基本問題。 過時的Qt WebKit引擎(~2015)缺少多年的安全修補。
原生二進位檔管理: Haukcode.DinkToPdf需要分發平台特定的二進位檔(libwkhtmltox.dylib)。 這使得部署,CI/CD流水線和容器化變得複雜。 IronPDF是自包含的,不需要外部二進位檔。
執行緒安全限制: 所需的SynchronizedConverter單例模式限制了架構的靈活性,並可能在負載下建立瓶頸。 IronPDF從設計上即具備執行緒安全,允許按需請求實例。
現代網頁標準: 有限的HTML5/CSS3支持和不安全的JavaScript執行限制了現代網頁內容的渲染能力。 IronPDF的Chromium引擎提供對現代網頁標準的支持。
長期可行性: 依賴於已放棄的技術會造成技術債務隨著時間的推移而累加。隨著專案向.NET 10和C# 14擴展至2026年,維持對未維護的wkhtmltopdf包裝的依賴變得越來越成問題。
優勢和考量
Haukcode.DinkToPdf的優勢
- 免費和開源: MIT授權無需授權費用
- 基本功能: 支持基本的HTML到PDF轉換
- 現有程式碼庫: 已經使用DinkToPdf的團隊所熟悉
Haukcode.DinkToPdf的考慮因素
- 重要的安全漏洞: CVE-2022-35583 無法修補
- 已廢棄的技術: 基於已停止的wkhtmltopdf
- 原生二進位檔相依性: 需要平台特定的DLL
- 執行緒安全問題: 需要單例模式
- 有限的網頁標準: 過時的Qt WebKit引擎
- 沒有專業支援: 僅限社群協助
- 技術債務: 依賴已放棄的專案風險累積
IronPDF的優勢
IronPDF考量
- 商業許可:生產使用需要商業許可
結論
Haukcode.DinkToPdf和IronPDF代表了.NET應用程式中PDF生成根本不同的方法。 Haukcode.DinkToPdf,作為包裝已停止的wkhtmltopdf二進位檔的已放棄的DinkToPdf專案的延續,存在重大安全漏洞(CVE-2022-35583),這些漏洞將永遠無法修補。 該程式庫需要原生二進位檔分發、用於執行緒安全的單例模式,而且僅提供有限的現代網頁標準支持。
IronPDF提供一個積極維護的替代方案,擁有現代Chromium引擎、定期的安全更新和執行緒安全的架構。 自包含的程式庫消除了原生二進位檔管理,同時提供完整的HTML5/CSS3/JavaScript支持。
正當組織計劃於.NET 10、C# 14和2026年前的應用程式開發之際,選擇繼續依賴具有關鍵且無法修復的漏洞的已廢棄技術,以及採用積極維護的解決方案,具備現代功能,顯著影響到安全姿勢和開發速度。 需要安全PDF生成、現代渲染或簡化部署的團隊將發現IronPDF能有效滿足這些需求。
從 免費試用 開始評估 IronPDF,並探索全面的文件以評估特定需求的適用性。
