比較

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.DinkToPdfIronPDF
重要CVECVE-2022-35583(CVSS 9.8,無法修復)積極修補
底層引擎wkhtmltopdf(Qt WebKit ~2015)Chromium(定期更新)
專案狀態放棄專案的分支積極開發
安全更新預期無更新定期發布
支持僅限社群專業支持

架構與引擎比較

根本的架構差異影響渲染品質、現代網頁標準支持和部署複雜性。

方面Haukcode.DinkToPdfIronPDF
渲染引擎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 Module
$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");
    }
}
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 Class
$vbLabelText   $csharpLabel

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

Haukcode.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 Module
$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");
    }
}
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 Class
$vbLabelText   $csharpLabel

Haukcode.DinkToPdf透過包含巢狀GlobalSettings來配置頁面設定。 屬性使用類似PaperKind.Letter的枚舉。

IronPDF在渲染器上直接使用RenderingOptions屬性。 屬性單獨設定(PdfPaperOrientation.Landscape)。 兩者對邊距大小使用毫米為單位。

IronPDF教程中了解有關渲染配置的更多資訊。

API映射參考

評估Haukcode.DinkToPdf遷移或比較功能時,開發人員可以參考此地圖顯示相當操作:

轉換器類別映射

Haukcode.DinkToPdfIronPDF
SynchronizedConverterChromePdfRenderer
BasicConverterChromePdfRenderer
PdfTools不適用
IConverter不適用

文件配置映射

Haukcode.DinkToPdfIronPDF
HtmlToPdfDocument方法調用
GlobalSettingsRenderingOptions
ObjectSettingsRenderingOptions
converter.Convert(doc)renderer.RenderHtmlAsPdf(html)

全球設定屬性映射

全球設定屬性IronPDF屬性
ColorModeRenderingOptions.GrayScale
OrientationRenderingOptions.PaperOrientation
PaperSizeRenderingOptions.PaperSize
Margins.TopRenderingOptions.MarginTop
Margins.BottomRenderingOptions.MarginBottom
Margins.LeftRenderingOptions.MarginLeft
Margins.RightRenderingOptions.MarginRight

物件設定屬性映射

物件設定屬性IronPDF等效
HtmlContentRenderHtmlAsPdf()的第一個參數
Page(URL)renderer.RenderUrlAsPdf(url)
HeaderSettings.Right = "[page]"TextHeader.RightText = "{page}"

佔位符語法差異

標頭/頁尾佔位符在不同程式庫中使用了不同的語法:

Haukcode.DinkToPdfIronPDF
[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 Sub
$vbLabelText   $csharpLabel

IronPDF(靈活):

// 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 Sub
$vbLabelText   $csharpLabel

IronPDF從設計上即具備執行緒安全,允許靈活的相依性注入模式,無需單例要求。

功能比較總結

功能Haukcode.DinkToPdfIronPDF
來源來源放棄專案的分支獨立開發
安全繼承自上遊的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的優勢

  • 主動安全修補: 定期更新 解決漏洞
  • 現代Chromium引擎: 現代網頁標準支持
  • 自包含: 無原生二進位檔相依性
  • 執行緒安全設計: 靈活的部署模式
  • 完整的HTML5/CSS3/JavaScript: 現代渲染能力
  • 專業支援: 專注的工程支援
  • 全面的資源: 豐富的教程文件

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,並探索全面的文件以評估特定需求的適用性。

請注意DinkToPdf和wkhtmltopdf是其各自擁有者的註冊商標。) 本站與DinkToPdf或wkhtmltopdf並無關聯、未被其認可或贊助。 所有產品名稱、標誌和品牌均為其各自所有者的財產。 比較僅供資訊參考,並反映了撰寫時公開的資訊。)}