Haukcode.DinkToPdf 与 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 使用SynchronizedConverter和PdfTools进行转换。 配置通过HtmlToPdfDocument对象进行管理,该对象包含用于页面选项(ColorMode、Orientation、PaperSize、Margins)的GlobalSettings和用于内容(HtmlContent 用于 HTML 字符串,Page 用于 URL)的ObjectSettings 。<代码>converter.Convert(doc)</代码方法返回原始 byte[] 数据。
该库需要特定平台的本地二进制文件:<代码>libwkhtmltox.dll</代码>(Windows)、<代码>libwkhtmltox.so</代码>(Linux)和<代码>libwkhtmltox.dylib</代码>(macOS)。 由于 wkhtmltopdf 的限制,线程安全要求在单例模式下使用SynchronizedConverter 。
探索铁质PDF
IronPDF 是一个独立开发的 .NET 库,使用现代 Chromium 渲染引擎。该库通过定期更新、专业支持和持续的安全补丁进行积极维护。
IronPDF 使用<代码>ChromePdfRenderer</代码作为其主要渲染类,并通过<代码>渲染选项</代码属性进行配置。 像 RenderHtmlAsPdf() 和 RenderUrlAsPdf() 这样的方法会返回 PdfDocument 对象,这些对象可以通过 SaveAs() 保存或作为 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);
}
}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");
}
}Haukcode.DinkToPdf 需要使用<代码>PdfTools</代码创建一个<代码>同步转换器</代码,使用嵌套的<代码>全局设置</代码和<代码>对象设置</代码对象构建一个<代码>HtmlToPdfDocument</代码,调用 Convert() 获取原始字节,然后使用 File.WriteAllBytes() 手动写入磁盘。WriteAllBytes() 手动写入磁盘。
IronPDF 创建了一个<代码>ChromePdfRenderer</代码,直接使用 HTML 字符串调用 RenderHtmlAsPdf() 并使用 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);
}
}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");
}
}Haukcode.DinkToPdf 使用与 ObjectSettings.Page 属性相同的<代码>HtmlToPdfDocument</代码结构来指定 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);
}
}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");
}
}Haukcode.DinkToPdf 通过嵌套 MarginSettings 对象的<代码>全局设置</代码配置页面设置。 属性使用枚举,如 Orientation.Landscape 和 PaperKind.Letter 。
IronPDF 直接在渲染器上使用<代码>渲染选项</代码属性。 属性可通过类型枚举(PdfPaperSize.Letter, PdfPaperOrientation.Landscape)单独设置(PaperSize, PaperOrientation, MarginTop等)。 两者都使用毫米作为余量单位。
在 IronPDF 教程中了解有关渲染配置的更多信息。
API 映射参考
对于评估 Haukcode.DinkToPdf 迁移或比较功能的开发人员,该映射显示了等价操作:
转换器类映射
| Haukcode.DinkToPdf | IronPDF |
|---|---|
| <代码>同步转换器</代码 | <代码>ChromePdfRenderer</代码 |
| <代码>BasicConverter</代码 | <代码>ChromePdfRenderer</代码 |
| <代码>PdfTools</代码 | 不适用 |
| <代码>IConverter</代码 | 不适用 |
文档配置映射
| Haukcode.DinkToPdf | IronPDF |
|---|---|
| <代码>HtmlToPdfDocument</代码 | 方法调用 |
| <代码>全局设置</代码 | <代码>渲染选项</代码 |
| <代码>对象设置</代码 | <代码>渲染选项</代码 |
| <代码>converter.Convert(doc)</代码 | <代码>renderer.RenderHtmlAsPdf(html)</代码 |
GlobalSettings 属性映射
| 全局设置属性 | IronPdf 属性 |
|---|---|
| <代码>ColorMode</代码 | <代码>RenderingOptions.GrayScale</代码 |
| <代码>方向</代码 | <代码>RenderingOptions.PaperOrientation</代码 |
| <代码>纸张大小</代码 | <代码>RenderingOptions.PaperSize</代码 |
| <代码>Margins.Top</代码 | <代码>RenderingOptions.MarginTop</代码 |
| <代码>Margins.Bottom</代码 | <代码>RenderingOptions.MarginBottom</代码 |
| <代码>Margins.Left</代码 | <代码>RenderingOptions.MarginLeft</代码 |
| <代码>Margins.Right</代码 | <代码>RenderingOptions.MarginRight</代码 |
对象设置属性映射
| 对象设置属性 | IronPdf 同等产品 |
|---|---|
| <代码>HtmlContent</代码 | RenderHtmlAsPdf() 的第一个参数 |
| <代码>页面</代码> (URL) | <代码>renderer.RenderUrlAsPdf(url)</代码 |
| <代码>HeaderSettings.Right = "[page]"</ 代码 | <代码>TextHeader.RightText = "{page}"</ 代码 |
占位符语法差异
不同库的页眉/页脚占位符使用不同的语法:
| Haukcode.DinkToPdf | IronPDF |
|---|---|
| <代码>[页面]</代码 | {page} |
| <代码>[toPage]</代码 | <代码>{总页数}</代码 |
| <代码>[日期]</代码 | <代码>{日期}</代码 |
线程安全和依赖注入
由于继承自 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()));
}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!
}IronPDF 在设计上是线程安全的,允许灵活的依赖注入模式,而不需要单例。
功能对比摘要
| 特征 | Haukcode.DinkToPdf | IronPDF |
|---|---|---|
| 来源 | 废弃项目的分叉 | 独立开发 |
| 安全性 | 从上游继承的 CVE(无法修复) | 主动打补丁,确保安全 |
| 社区与支持 | 少量零星翻译 | 规模大、活跃、敬业 |
| 功能与更新 | 有限且零星 | 活跃开发的常规 |
| 支持多线程 | 需要单例模式 | 全面支持和优化 |
| 本地二进制文件 | 要求(特定平台) | 自成一体 |
| HTML5/CSS3 | 有限的 | 支持 |
| JavaScript语言 | 有限的 | 完整的 V8 引擎 |
| 许可 | 麻省理工学院(免费) | 免费试用版商业版 |
团队何时考虑从 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.dll 、 libwkhtmltox.so 、 libwkhtmltox.dylib )。 这使得部署、CI/CD 管道和容器化变得复杂。 IronPdf 是独立的,没有外部二进制文件。
线程安全限制:所需的SynchronizedConverter单例模式限制了架构灵活性,并且可能在负载下造成瓶颈。IronPDF采用线程安全设计,允许按请求实例。
现代网络标准: HTML5/CSS3 支持有限以及 JavaScript 执行不安全,限制了现代网络内容的渲染能力。IronPDF的 Chromium 引擎提供当前网络标准支持。
长期可行性:对已弃用技术的依赖会造成技术债务,并且随着时间的推移而不断累积。随着项目在 2026 年前逐步扩展到 .NET 10 和 C# 14,继续依赖不再维护的 wkhtmltopdf 封装库将变得越来越成问题。
优势和考虑因素
Haukcode.DinkToPdf 的优势
-免费开源:采用 MIT 许可证,无需支付任何许可费用 -基本功能:支持基本的 HTML 转 PDF 转换 -现有代码库:对于已经使用 DinkToPdf 的团队来说比较熟悉
Haukcode.DinkToPdf 注意事项
-严重安全漏洞: CVE-2022-35583 无法修复 -废弃技术:基于已停止使用的 wkhtmltopdf 构建 -本地二进制依赖项:需要特定于平台的 DLL 文件 -螺纹安全问题:需要单例模式 -受限的 Web 标准:过时的 Qt WebKit 引擎 -不提供专业支持:仅提供社区援助 技术债务:对废弃项目的依赖加剧了风险
IronPDF的优势
-主动安全补丁:定期更新以修复漏洞 -现代 Chromium 引擎:支持当前 Web 标准 -自包含:无原生二进制依赖项 -线程安全设计:灵活的部署模式 -全面支持 HTML5/CSS3/JavaScript:具备现代渲染功能 -专业支持:专属工程支持 -丰富的资源:大量的教程和文档
IronPDF注意事项
-商业许可:生产用途必需
结论
Haukcode.DinkToPdf 和IronPDF代表了在 .NET 应用程序中生成 PDF 的根本不同方法。 Haukcode.DinkToPdf 作为已停止开发的 DinkToPdf 项目的延续,封装了已停止开发的 wkhtmltopdf 二进制文件,存在严重的安全漏洞 (CVE-2022-35583),这些漏洞永远不会得到修复。 该库需要本地二进制分发、单例模式以保证线程安全,并提供有限的现代网络标准支持。
IronPDF 提供了一个积极维护的替代方案,具有现代 Chromium 引擎、定期安全更新和线程安全架构。 自足式库消除了本地二进制管理,同时提供全面的 HTML5/CSS3/JavaScript 支持。
随着企业对.NET 10、C# 14 以及 2026 年之前的应用程序开发进行规划,在保持对存在严重无法修复漏洞的废弃技术的依赖性和采用具有现代功能的积极维护的解决方案之间做出选择,会对安全态势和开发速度产生重大影响。 需要安全生成 PDF、现代渲染或简化部署的团队会发现IronPDF能有效满足这些要求。