跳過到頁腳內容
MIGRATION GUIDES

Migrating from Haukcode.DinkToPdf to IronPDF

Haukcode.DinkToPdf 是曾經流行的 DinkToPdf 庫的延續,它使用 wkhtmltopdf 二進位檔案將 HTML 轉換為 PDF,供 .NET 應用程式使用。 儘管 Haukcode.DinkToPdf 在原始專案停滯後繼續支援 .NET Core,但它由於其上游依賴項而存在嚴重的安全性問題。 wkhtmltopdf 專案已於 2023 年 1 月存檔,因此這些問題將永遠無法解決。

本指南提供了從 Haukcode.DinkToPdf 到 IronPDF 的完整遷移路徑,包括逐步說明、程式碼比較和實用範例,旨在幫助專業的 .NET 開發人員消除 PDF 生成工作流程中的安全風險。

嚴重安全警告:CVE-2022-35583

Haukcode.DinkToPdf 從 wkhtmltopdf 繼承了一個無法解決的重大安全漏洞:

CVE-2022-35583 - 嚴重 SSRF 漏洞 (CVSS 9.8)

wkhtmltopdf 庫(以及所有封裝庫,包括 Haukcode.DinkToPdf)存在伺服器端請求偽造 (SSRF) 漏洞:

攻擊途徑:惡意 HTML 內容可導致伺服器取得內部資源。

  • AWS 元資料攻擊:可存取http://169.254.169.254竊取 AWS 憑證 -內部網路存取:可掃描和存取內部服務 -本機檔案包含:可透過file://協定讀取本機文件 影響:可能完全接管基礎設施

由於 wkhtmltopdf 已於 2023 年停止維護並存檔,因此漏洞無法修復。其最後一個版本是 2020 年發布的 0.12.6 版本。

IronPDF 與 Haukcode.DinkToPdf:功能對比

了解架構差異有助於技術決策者評估遷移投資:

方面 Haukcode.DinkToPdf IronPDF
底層引擎 wkhtmltopdf(Qt WebKit ~2015) Chromium(定期更新)
安全狀態 CVE-2022-35583(嚴重,無法修復) 已積極打補丁
專案狀態 廢棄項目的分支 積極開發
HTML5/CSS3 有限的 全力支持
JavaScript 有限、不安全 全V8發動機
本地二進位文件 必需(平台特定) 自給自足
螺紋安全 需要單例模式 螺紋安全設計
支援 僅限社區 專業支援
更新 預計不會發生 定期發布
執照 麻省理工學院(免費) 提供免費試用的商業廣告

快速入門:Haukcode.DinkToPdf 到 IronPDF 的遷移

透過這些基礎步驟,遷移工作可以立即開始。

步驟 1:移除 DinkToPdf 和原生二進位文件

移除 Haukcode.DinkToPdf NuGet 套件:

# Remove NuGet packages
dotnet remove package DinkToPdf
dotnet remove package Haukcode.DinkToPdf
dotnet remove package Haukcode.WkHtmlToPdf-DotNet
# Remove NuGet packages
dotnet remove package DinkToPdf
dotnet remove package Haukcode.DinkToPdf
dotnet remove package Haukcode.WkHtmlToPdf-DotNet
SHELL

從專案中刪除本地二進位檔案:

  • libwkhtmltox.dll (Windows)
  • libwkhtmltox.so (Linux)
  • libwkhtmltox.dylib (macOS)

步驟 2:安裝 IronPDF

# Install IronPDF
dotnet add package IronPdf
# Install IronPDF
dotnet add package IronPdf
SHELL

步驟 3:更新命名空間

將 DinkToPdf 命名空間替換為 IronPdf:

// Before (Haukcode.DinkToPdf)
using DinkToPdf;
using DinkToPdf.Contracts;

// After (IronPDF)
using IronPdf;
using IronPdf.Rendering;  // For RenderingOptions
// Before (Haukcode.DinkToPdf)
using DinkToPdf;
using DinkToPdf.Contracts;

// After (IronPDF)
using IronPdf;
using IronPdf.Rendering;  // For RenderingOptions
$vbLabelText   $csharpLabel

步驟 4:初始化許可證

在應用程式啟動時新增許可證初始化:

IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
$vbLabelText   $csharpLabel

程式碼遷移範例

基本的 HTML 轉 PDF 轉換

最基本的操作揭示了這些 .NET 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() {
                    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);
    }
}
$vbLabelText   $csharpLabel

IronPDF 方法:

// 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");
    }
}
$vbLabelText   $csharpLabel

Haukcode.DinkToPdf 需要使用PdfTools建立一個SynchronizedConverter ,使用巢狀的GlobalSettingsObjects建構一個HtmlToPdfDocument ,加入一個帶有HtmlContentObjectSettings ,呼叫converter.Convert()取得原始位元組,然後使用File.WriteAllBytes()

IronPDF 將此簡化為三行程式碼:建立一個ChromePdfRenderer ,呼叫RenderHtmlAsPdf() ,然後使用內建的SaveAs()方法。

如需更進階的 HTML 轉 PDF 場景,請參閱HTML 轉 PDF 轉換指南

將 URL 轉換為 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);
    }
}
$vbLabelText   $csharpLabel

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");
    }
}
$vbLabelText   $csharpLabel

Haukcode.DinkToPdf 使用與ObjectSettings.Page相同的文件建構模式來處理 URL。 IronPDF 提供了一個專門的RenderUrlAsPdf()方法,可以清楚地表達意圖。

查看指向 PDF 文件的 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);
    }
}
$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.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");
    }
}
$vbLabelText   $csharpLabel

Haukcode.DinkToPdf 將設定嵌套在GlobalSettings中,並使用單獨的MarginSettings物件。 IronPDF 提供直接的RenderingOptions屬性,其名稱清晰明了,例如PaperSizePaperOrientation和單獨的邊距屬性。

Haukcode.DinkToPdf API 到 IronPDF 映射參考

此映射透過顯示直接的 API 等效項來加速遷移:

轉換器類別映射

Haukcode.DinkToPdf IronPDF 筆記
SynchronizedConverter ChromePdfRenderer 線程安全,無需單例模式
BasicConverter ChromePdfRenderer 同一個類別處理這兩個問題
PdfTools 不適用 不需要
IConverter 不適用 直接使用渲染器

文檔配置映射

Haukcode.DinkToPdf IronPDF 筆記
HtmlToPdfDocument 方法調用 直接使用RenderHtmlAsPdf()
GlobalSettings RenderingOptions 設定渲染前
ObjectSettings RenderingOptions 合併成一個
converter.Convert(doc) renderer.RenderHtmlAsPdf(html) 返回PdfDocument

全域設定屬性映射

全域設定屬性 IronPDF屬性 筆記
ColorMode RenderingOptions.GrayScale 布林值,設定為true表示灰階模式
Orientation RenderingOptions.PaperOrientation PortraitLandscape
PaperSize RenderingOptions.PaperSize 使用PdfPaperSize枚舉
Margins.Top RenderingOptions.MarginTop 單位:毫米
Margins.Bottom RenderingOptions.MarginBottom 單位:毫米
Margins.Left RenderingOptions.MarginLeft 單位:毫米
Margins.Right RenderingOptions.MarginRight 單位:毫米

物件設定屬性映射

ObjectSettings 屬性 IronPDF當量 筆記
HtmlContent RenderHtmlAsPdf()函數的第一個參數 直接參數
Page (URL) renderer.RenderUrlAsPdf(url) 單獨方法
HeaderSettings.Right = "[page]" TextHeader.RightText = "{page}" 不同的佔位符語法

佔位符語法遷移

Haukcode.DinkToPdf IronPDF 筆記
[page] {page} 目前頁碼
[toPage] {total-pages} 總頁數
[date] {date} 目前日期

常見遷移問題及解決方案

問題 1:單例要求

Haukcode.DinkToPdf:由於原生 wkhtmltopdf 二進位檔案存在線程安全問題,因此需要將SynchronizedConverter作為單例使用。

解決方案: IronPDF 的ChromePdfRenderer從設計上就保證了線程安全——無需單例模式:

// Before (DinkToPdf) - MUST be singleton
services.AddSingleton(typeof(IConverter), new SynchronizedConverter(new PdfTools()));

// After (IronPDF) - Can be singleton or transient (both work)
services.AddSingleton<IPdfService, IronPdfService>();
// Or services.AddTransient<IPdfService, IronPdfService>() - both are safe!
// Before (DinkToPdf) - MUST be singleton
services.AddSingleton(typeof(IConverter), new SynchronizedConverter(new PdfTools()));

// After (IronPDF) - Can be singleton or transient (both work)
services.AddSingleton<IPdfService, IronPdfService>();
// Or services.AddTransient<IPdfService, IronPdfService>() - both are safe!
$vbLabelText   $csharpLabel

問題 2:原生二進位依賴項

Haukcode.DinkToPdf:需要特定於平台的本機程式庫(libwkhtmltox.dll/so/dylib)。

解決方案: IronPDF 是一個獨立的程序,沒有任何原生二元依賴項。 遷移完成後刪除以下檔案:

  • libwkhtmltox.dll (Windows)
  • libwkhtmltox.so (Linux)
  • libwkhtmltox.dylib (macOS)

問題 3:退貨類型差異

Haukcode.DinkToPdf: converter.Convert()直接回傳byte[]

解決方案: IronPDF 傳回一個PdfDocument對象,該物件具有多個輸出選項:

var pdf = renderer.RenderHtmlAsPdf(html);
byte[] bytes = pdf.BinaryData;  // Get bytes
pdf.SaveAs("output.pdf");       // Or save directly
var pdf = renderer.RenderHtmlAsPdf(html);
byte[] bytes = pdf.BinaryData;  // Get bytes
pdf.SaveAs("output.pdf");       // Or save directly
$vbLabelText   $csharpLabel

問題 4:頁首/頁尾佔位符語法

Haukcode.DinkToPdf:使用方括號語法,如[page][toPage]

解決方案:更新 IronPDF 的花括號佔位符:

// Before (DinkToPdf)
HeaderSettings = { Right = "Page [page] of [toPage]" }

// After (IronPDF)
renderer.RenderingOptions.TextHeader = new TextHeaderFooter
{
    RightText = "Page {page} of {total-pages}"
};
// Before (DinkToPdf)
HeaderSettings = { Right = "Page [page] of [toPage]" }

// After (IronPDF)
renderer.RenderingOptions.TextHeader = new TextHeaderFooter
{
    RightText = "Page {page} of {total-pages}"
};
$vbLabelText   $csharpLabel

Haukcode.DinkToPdf 遷移清單

遷移前任務

審核您的程式碼庫,找出所有 DinkToPdf 的使用情況:

# Find DinkToPdf namespace usage
grep -r "using DinkToPdf\|using Haukcode" --include="*.cs" .

# Find converter usage
grep -r "SynchronizedConverter\|BasicConverter\|HtmlToPdfDocument" --include="*.cs" .

# Find native library loading
grep -r "wkhtmltopdf\|libwkhtmltox" --include="*.cs" --include="*.csproj" .

# Find GlobalSettings/ObjectSettings usage
grep -r "GlobalSettings\|ObjectSettings\|MarginSettings" --include="*.cs" .
# Find DinkToPdf namespace usage
grep -r "using DinkToPdf\|using Haukcode" --include="*.cs" .

# Find converter usage
grep -r "SynchronizedConverter\|BasicConverter\|HtmlToPdfDocument" --include="*.cs" .

# Find native library loading
grep -r "wkhtmltopdf\|libwkhtmltox" --include="*.cs" --include="*.csproj" .

# Find GlobalSettings/ObjectSettings usage
grep -r "GlobalSettings\|ObjectSettings\|MarginSettings" --include="*.cs" .
SHELL

記錄目前的GlobalSettingsObjectSettings配置。 找出所有可以刪除的本機庫載入程式碼。

程式碼更新任務

  1. 刪除 DinkToPdf NuGet 套件
  2. 安裝 IronPdf NuGet 套件
  3. 將命名空間導入從DinkToPdf更新為IronPdf
  4. SynchronizedConverter替換為ChromePdfRenderer
  5. HtmlToPdfDocument模式轉換為直接方法調用
  6. GlobalSettings轉換為RenderingOptions
  7. ObjectSettings轉換為RenderingOptions
  8. 更新佔位符語法( [page]{page}[toPage]{total-pages}
  9. 新增 IronPDF 啟動時許可證初始化功能

基礎設施清理任務

  1. 刪除本機二進位(libwkhtmltox.*)
  2. 移除本機庫載入程式碼
  3. 如果存在,則移除 CustomAssemblyLoadContext。
  4. 更新依賴注入(不再需要單例模式)
  5. 移除本地二進位檔案的平台偵測程式碼

遷移後測試

遷移完成後,請確認以下幾個面向:

  • 測試 HTML 到 PDF 的轉換
  • 測試 URL 到 PDF 的轉換
  • 檢查頁面設定(大小、方向、邊距)
  • 核對頁首和頁尾是否包含佔位符
  • 使用實際的 HTML 範本進行測試
  • 負載下的效能測試

遷移到 IronPDF 的主要優勢

從 Haukcode.DinkToPdf 遷移到 IronPDF 可帶來以下幾個關鍵優勢:

安全性:消除 CVE-2022-35583 (SSRF) 和其他 wkhtmltopdf 漏洞,這些漏洞永遠不會被修復。

現代渲染引擎:使用持續更新的 Chromium 內核,而不是 2015 年就已棄用的 Qt WebKit 內核。完全支援 HTML5、CSS3 和 JavaScript。

無本地二進位檔案:自包含庫,無需管理任何平台特定的 DLL 檔案。 簡化了在 Windows、Linux 和 macOS 上的部署。

線程安全:沒有單例要求-可以自由地以任何模式使用ChromePdfRenderer ,包括按請求實例化。

更簡單的 API:直接呼叫方法( RenderHtmlAsPdf()RenderUrlAsPdf() ),而不是複雜的文檔物件建構。

積極開發:隨著 .NET 10 和 C# 14 的普及,IronPDF 將持續更新,確保與目前和未來的 .NET 版本相容。

Curtis Chau
技術撰稿人

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

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