DinkToPdf 与 IronPDF:技术比较指南
当 .NET 开发人员评估 PDF 生成库时,DinkToPdf 是一个众所周知的开源选择,它使用 wkhtmltopdf 二进制文件。 然而,严重的安全漏洞、线程安全问题以及缺乏持续维护,促使许多团队考虑其他方案。IronPDF提供了一个现代化的、积极维护的解决方案,它采用 Chromium 渲染引擎,并且没有原生二进制依赖项。
本次比较从相关技术方面考察了这两个库,以帮助专业开发人员和架构师根据其 .NET PDF 需求做出明智的决策。
了解 DinkToPdf。
DinkToPdf 是 C# 生态系统中的一个开源库,它使用 wkhtmltopdf 的包装器实现 HTML 到 PDF 的转换。 该库使用 MIT 许可,可在各种项目中进行集成和修改。
DinkToPdf 封装了 wkhtmltopdf 的功能,允许开发人员使用 CSS 和JavaScript将 HTML 内容转换为 PDF 文档。 但是,该库继承了与 wkhtmltopdf 二进制文件相关的所有安全漏洞和限制,包括关键的 CVE-2022-35583 SSRF(服务器端请求伪造)问题。 wkhtmltopdf 项目已于 2020 年放弃,DinkToPdf 本身最近一次更新是在 2018 年。
该库需要部署特定平台的本地二进制文件(Windows:libwkhtmltox.dll;Linux:libwkhtmltox.so;macOS:libwkhtmltox.dylib),从而造成部署复杂性和维护开销。 此外,DinkToPdf 显然是非线程安全的,即使在使用同步转换器封装器的情况下,也会导致并发执行环境中记录的失败。
了解IronPDF
IronPDF 是一个商用 .NET PDF 库,使用现代 Chromium 渲染引擎进行 HTML 到 PDF 的转换。 该库提供完整的 PDF 生成和操作功能,无需依赖外部本地二进制文件。
IronPDF 支持 .NET Framework 4.6.2+、.NET Core 3.1+ 和 .NET5/6/7/8/9,采用纯 NuGet 包部署模式,无需本地依赖性管理。 该库专为线程安全的并发操作而设计,能够可靠地并行生成 PDF,而不会出现与DinkToPdf相关的崩溃问题。
安全性比较
安全问题是这些 .NET PDF 库之间最显著的区别。
| 安全方面 | DinkToPdf | IronPDF |
|---|---|---|
| 已知漏洞 | CVE-2022-35583 (SSRF) | 无已知漏洞 |
| 漏洞状态 | 未修补 | 通过设计减轻 |
| 核心依赖关系 | wkhtmltopdf (2020 年放弃) | 现代 Chromium |
| 安全更新 | 无(项目已放弃) | 定期更新 |
DinkToPdf 从 wkhtmltopdf 继承了 CVE-2022-35583 服务器端请求伪造漏洞。 该漏洞允许攻击者访问内部网络资源,给处理不受信任的 HTML 内容的应用程序带来巨大的安全风险。 鉴于 wkhtmltopdf 已被弃用,这些漏洞将永远不会收到补丁。
架构和渲染引擎比较
| 方面 | DinkToPdf | IronPDF |
|---|---|---|
| 渲染引擎 | 过时的 WebKit(约 2015 年) | 现代 Chromium |
| 线程安全 | 并发使用中的崩溃 | 完全线程安全 |
| 本地依赖关系 | 特定平台的二进制文件 | 纯 NuGet 软件包 |
| CSS支持 | 无 Flexbox/网格 | 完整的 CSS3 |
| JavaScript语言 | 有限、不一致 | 支持 |
| 维护 | 遗弃(2018) | 积极维护 |
| 支持 | 仅限社区 | 专业支持 |
DinkToPdf 的 wkhtmltopdf 依赖项使用的是大约 2015 年的过时 WebKit 引擎。这就造成了渲染限制,导致 Flexbox 和网格布局等现代 CSS 功能无法正确渲染。JavaScript的执行能力有限且不稳定,对动态内容产生的结果不可靠。
IronPDF 使用现代的 Chromium 引擎,可以完全按照当代浏览器的显示方式渲染 HTML,完全支持 CSS3(包括 Flexbox 和 Grid 布局),以及可靠的JavaScript执行(可配置等待时间)。
代码比较:常见的 PDF 操作
基本 HTML 到 PDF 的转换
最基本的操作展示了 API 复杂性的差异。
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 = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>",
WebSettings = { DefaultEncoding = "utf-8" }
}
}
};
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 = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>",
WebSettings = { DefaultEncoding = "utf-8" }
}
}
};
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 ObjectSettings() With {
.HtmlContent = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>",
.WebSettings = New WebSettings() With {
.DefaultEncoding = "utf-8"
}
}
}
}
Dim pdf As Byte() = converter.Convert(doc)
File.WriteAllBytes("output.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.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 ClassDinkToPdf 需要使用PdfTools创建同步转换器,使用全局设置和对象设置构建HtmlToPdfDocument,配置 WebSettings ,转换为 byte[] 并手动写入文件。IronPDF 创建了一个ChromePdfRenderer,调用 RenderHtmlAsPdf() 并保存--三行对十五行。
有关高级 HTML 渲染选项,请浏览 HTML 到 PDF 转换指南。
URL到PDF转换
将网页截取为 PDF 显示了类似的复杂性差异。
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 ClassDinkToPdf 使用对象设置中的 Page 属性指定 URL,需要相同的文档包装结构。IronPDF提供了专门的 RenderUrlAsPdf() 方法,用于直接渲染 URL。
在 URL to PDF 文档中了解有关 URL 呈现的更多信息。
自定义页面设置和页边距
配置页面方向和页边距演示了设置 API 的差异。
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.A4,
Margins = new MarginSettings { Top = 10, Bottom = 10, Left = 15, Right = 15 }
},
Objects = {
new ObjectSettings() {
HtmlContent = "<h1>Custom PDF</h1><p>Landscape orientation with custom margins.</p>",
WebSettings = { DefaultEncoding = "utf-8" }
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("custom.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.A4,
Margins = new MarginSettings { Top = 10, Bottom = 10, Left = 15, Right = 15 }
},
Objects = {
new ObjectSettings() {
HtmlContent = "<h1>Custom PDF</h1><p>Landscape orientation with custom margins.</p>",
WebSettings = { DefaultEncoding = "utf-8" }
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("custom.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.A4,
.Margins = New MarginSettings() With {
.Top = 10,
.Bottom = 10,
.Left = 15,
.Right = 15
}
},
.Objects = {
New ObjectSettings() With {
.HtmlContent = "<h1>Custom PDF</h1><p>Landscape orientation with custom margins.</p>",
.WebSettings = New WebSettings() With {
.DefaultEncoding = "utf-8"
}
}
}
}
Dim pdf As Byte() = converter.Convert(doc)
File.WriteAllBytes("custom.pdf", pdf)
End Sub
End ModuleIronPDF:
// 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 = 15;
renderer.RenderingOptions.MarginRight = 15;
var pdf = renderer.RenderHtmlAsPdf("<h1>Custom PDF</h1><p>Landscape orientation with custom margins.</p>");
pdf.SaveAs("custom.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 = 15;
renderer.RenderingOptions.MarginRight = 15;
var pdf = renderer.RenderHtmlAsPdf("<h1>Custom PDF</h1><p>Landscape orientation with custom margins.</p>");
pdf.SaveAs("custom.pdf");
}
}Imports IronPdf
Imports IronPdf.Rendering
Imports System
Module Program
Sub Main()
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape
renderer.RenderingOptions.MarginTop = 10
renderer.RenderingOptions.MarginBottom = 10
renderer.RenderingOptions.MarginLeft = 15
renderer.RenderingOptions.MarginRight = 15
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Custom PDF</h1><p>Landscape orientation with custom margins.</p>")
pdf.SaveAs("custom.pdf")
End Sub
End ModuleDinkToPdf 将页面设置嵌入全局设置中,包括嵌套的边距设置对象。IronPDF直接在渲染器上使用渲染选项属性,并通过单独的页边距属性(MarginTop, MarginBottom, MarginLeft, MarginRight )进行更清晰的配置。
方法映射参考
对于评估DinkToPdf迁移或比较功能的开发人员,该映射显示了等价操作:
核心类映射
| DinkToPdf | IronPDF |
|---|---|
同步转换器 | |
BasicConverter | ChromePdfRenderer |
PdfTools | 不需要 |
HtmlToPdfDocument | 不需要 |
全局设置 | 渲染选项 |
对象设置 | 渲染选项 |
边距设置 | 个别边距属性 |
设置映射
| DinkToPdf | IronPDF |
|---|---|
GlobalSettings.PaperSize | RenderingOptions.PaperSize |
GlobalSettings.Orientation | RenderingOptions.PaperOrientation |
GlobalSettings.Margins.Top = 10 | RenderingOptions.MarginTop = 10 |
ObjectSettings.HtmlContent | RenderHtmlAsPdf(html) |
对象设置.页面 | RenderUrlAsPdf(url) |
converter.Convert(doc) 返回 byte[] | pdf.BinaryData</code>或<code>pdf.SaveAs() |
页眉/页脚占位符语法
| DinkToPdf | IronPDF |
|---|---|
[页面] | {page} |
[toPage] | {总页数} |
[日期] | {日期} |
[时间] | {时间} |
[标题] | {html-title} |
功能对比摘要
| 特征 | DinkToPdf | IronPDF |
|---|---|---|
| HTML 至 PDF | ✅(过时的引擎) | ✅(Chromium) |
| URL 至 PDF | ✅ | ✅ |
| 自定义页边距 | ✅ | ✅ |
| 页眉/页脚 | ✅(有限) | ✅ (完整 HTML) |
| CSS3 | ❌ 有限公司 | ✅ 全文 |
| Flexbox/Grid | ❌ | ✅ |
| JavaScript | ⚠️ 有限公司 | ✅ 全文 |
| PDF 操作 | ❌ | ✅ |
| 表格填写 | ❌ | ✅ |
| 数字签名 | ❌ | ✅ |
| 加密 | ❌ | ✅ |
| 水印 | ❌ | ✅ |
| 合并/拆分 | ❌ | ✅ |
团队何时考虑从DinkToPdf迁移到 IronPDF?
开发团队评估从DinkToPdf过渡到IronPDF有几个原因:
安全合规性要求: wkhtmltopdf 中的 CVE-2022-35583 SSRF 漏洞会给处理不受信任的 HTML 内容的应用程序带来不可接受的风险。 安全审计发现了这一漏洞,由于没有可用的补丁,团队必须进行迁移以满足合规性要求。
线程安全问题:即使使用SynchronizedConverter ,DinkToPdf 在并发执行环境中也会崩溃。 需要并行生成 PDF 的生产应用程序会遇到无法在DinkToPdf架构内解决的可靠性问题。
现代 CSS 要求:使用现代 CSS 布局(Flexbox、Grid)的应用程序发现DinkToPdf的过时 WebKit 引擎无法正确渲染这些布局。 构建现代网络界面的团队无法生成准确的 PDF 格式。
本地二进制文件管理:对特定于平台的libwkhtmltox二进制文件的要求,使得在 Windows、Linux 和 macOS 环境中部署变得复杂。 容器部署和 CI/CD 管道需要对本地依赖关系进行额外配置。
已停止维护:DinkToPdf的最后一次更新是在 2018 年,而 wkhtmltopdf 自 2020 年以来就已停止维护,因此团队无法依赖其错误修复、安全补丁或与现代 .NET 版本兼容的更新。
JavaScript 可靠性:使用DinkToPdf从动态内容生成 PDF 的应用程序会遇到JavaScript执行不一致的问题。IronPDF的 Chromium 引擎可提供可靠的JavaScript执行,并可配置等待时间。
优势和考虑因素
DinkToPdf的优势
-开源: MIT 许可证允许免费使用和修改 -简单易用:适用于简单用例的基本 HTML 转 PDF 转换 -社区:拥有成熟的用户群体和社区资源
DinkToPdf注意事项
-安全漏洞: CVE-2022-35583 SSRF 漏洞,未修复 -已弃用项目:自 2018 年以来未更新,wkhtmltopdf 自 2020 年起已弃用。 -线程安全:尽管使用了 SynchronizedConverter,但在并发使用时仍然崩溃 -原生依赖项:需要特定平台的二进制文件 -渲染方式过时:使用 2015 年的 WebKit 引擎,不支持 Flexbox/Grid。
- JavaScript 功能受限:执行不稳定
IronPDF的优势
-现代渲染:采用 Chromium 引擎,完全支持CSS3和 JavaScript -线程安全:专为并发操作而设计 -无原生依赖:纯 NuGet 包部署 -主动维护:定期更新和安全补丁 -专业支持:提供企业级支持 -扩展功能: PDF 编辑、表单、签名、加密、水印 -丰富的资源:全面的教程和文档
IronPDF注意事项
-商业许可:生产用途需要获得许可
结论
DinkToPdf 和IronPDF代表了在 .NET 应用程序中生成 PDF 的根本不同方法。DinkToPdf提供了开源的可访问性,但存在严重的安全漏洞、线程安全问题,并且处于废弃维护状态,这给生产带来了巨大风险。
IronPdf 采用 Chromium 渲染引擎、线程安全架构、无本地依赖性和主动维护,为您提供了一个现代化的选择。 对于需要安全合规性、并发 PDF 生成、现代 CSS 支持或可靠JavaScript执行的团队,IronPDF 可满足这些特定要求。
随着企业对.NET 10、C# 14 以及 2026 年之前的应用程序开发进行规划,在已知漏洞的废弃库和积极维护的解决方案之间做出选择,既会影响当前的功能,也会影响长期的安全态势。 团队应根据每个库的特点评估自己的具体要求--安全合规性、并发需求、CSS 复杂性和部署限制。