跳至頁尾內容
移民指南

從 Haukcode.DinkToPdf 遷移到 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.DinkToPdfIronPDF
底層引擎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.DinkToPdfIronPDF筆記
SynchronizedConverterChromePdfRenderer線程安全,無需單例模式
BasicConverterChromePdfRenderer同一個類別處理這兩個問題
PdfTools不適用不需要
IConverter不適用直接使用渲染器

文檔配置映射

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

全域設定屬性映射

全域設定屬性IronPDF屬性筆記
ColorModeRenderingOptions.GrayScale布林值,設定為true表示灰階模式
OrientationRenderingOptions.PaperOrientationPortraitLandscape
PaperSizeRenderingOptions.PaperSize使用PdfPaperSize枚舉
Margins.TopRenderingOptions.MarginTop單位:毫米
Margins.BottomRenderingOptions.MarginBottom單位:毫米
Margins.LeftRenderingOptions.MarginLeft單位:毫米
Margins.RightRenderingOptions.MarginRight單位:毫米

物件設定屬性映射

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

佔位符語法遷移

Haukcode.DinkToPdfIronPDF筆記
[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擁有卡爾頓大學電腦科學學士學位,專長於前端開發,精通Node.js、TypeScript、JavaScript和React。他熱衷於打造直覺美觀的使用者介面,喜歡使用現代框架,並擅長撰寫結構清晰、視覺效果出色的使用者手冊。

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