从 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 版。
IronPDFvs Haukcode.DinkToPdf:功能比较
了解架构差异有助于技术决策者评估迁移投资:
| 方面 | Haukcode.DinkToPdf | IronPDF |
|---|---|---|
| 底层引擎 | wkhtmltopdf (Qt WebKit ~2015) | Chromium (定期更新) |
| 安全状态 | CVE-2022-35583(CRITICAL,不可修复) | 积极修补 |
| 项目状态 | 废弃项目的分叉 | 积极开发 |
| 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从您的项目中删除本地二进制文件:
- <代码>libwkhtmltox.dll</代码>(Windows)
libwkhtmltox.so(Linux)- <代码>libwkhtmltox.dylib</代码>(macOS)
步骤2:安装IronPDF
# Install IronPDF
dotnet add package IronPdf# Install IronPDF
dotnet add package IronPdf步骤 3:更新命名空间
用 IronPdf 替换 DinkToPdf 命名空间:
// 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步骤 4:初始化许可证
在应用程序启动时添加许可证初始化:
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";代码迁移示例
基本 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);
}
}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</代码创建一个 SynchronizedConverter, 使用嵌套的<代码>全局设置</代码和 Objects 构建一个 HtmlToPdfDocument, 添加一个<代码>对象设置</代码和 HtmlContent, 调用 converter.Convert() 来转换 HTML 文档。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);
}
}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 相同的文档构建模式来构建 URL。IronPDF提供了专门的 RenderUrlAsPdf() 方法,可以清晰地表达意图。
请浏览 URL to 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.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 对象中。IronPDF直接提供了名称清晰的<代码>渲染选项</代码属性,如 PaperSize, PaperOrientation 和各个页边距属性。
Haukcode.DinkToPdf API 到IronPDF的映射参考
这种映射通过显示直接的 API 对应关系来加速迁移:
转换器类映射
| Haukcode.DinkToPdf | IronPDF | 备注 |
|---|---|---|
| <代码>同步转换器</代码 | <代码>ChromePdfRenderer</代码 | 线程安全,无需单例 |
| <代码>BasicConverter</代码 | <代码>ChromePdfRenderer</代码 | 同一类别同时处理 |
| <代码>PdfTools</代码 | 不适用 | 不需要 |
| <代码>IConverter</代码 | 不适用 | 直接使用呈现器 |
文档配置映射
| Haukcode.DinkToPdf | IronPDF | 备注 |
|---|---|---|
| <代码>HtmlToPdfDocument</代码 | 方法调用 | 直接使用 RenderHtmlAsPdf() |
| <代码>全局设置</代码 | <代码>渲染选项</代码 | 渲染前设置 |
| <代码>对象设置</代码 | <代码>渲染选项</代码 | 合二为一 |
| <代码>converter.Convert(doc)</代码 | <代码>renderer.RenderHtmlAsPdf(html)</代码 | 返回 PdfDocument |
GlobalSettings 属性映射
| 全局设置属性 | IronPdf 属性 | 备注 |
|---|---|---|
| <代码>ColorMode</代码 | <代码>RenderingOptions.GrayScale</代码 | 布尔,设置 true 表示灰度 |
| <代码>方向</代码 | <代码>RenderingOptions.PaperOrientation</代码 | <代码>肖像</代码>或<代码>风景</代码 |
| <代码>纸张大小</代码 | <代码>RenderingOptions.PaperSize</代码 | 使用 PdfPaperSize 枚举 |
| <代码>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]</代码 | <代码>{总页数}</代码 | 总页数 |
| <代码>[日期]</代码 | <代码>{日期}</代码 | 当前日期 |
常见迁移问题和解决方案
问题 1:单例需求
Haukcode.DinkToPdf:由于本地 wkhtmltopdf 二进制程序的线程安全问题,需要<代码>同步转换器</代码作为单例。
解决方案: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!问题 2:本地二进制依赖关系
Haukcode.DinkToPdf:需要特定平台的本地库(libwkhtmltox.dll/so/dylib)。
解决方案:IronPDF是独立的,没有本地二进制依赖关系。 迁移后删除这些文件:
- <代码>libwkhtmltox.dll</代码>(Windows)
libwkhtmltox.so(Linux)- <代码>libwkhtmltox.dylib</代码>(macOS)
问题 3:返回类型差异
Haukcode.DinkToPdf:converter.Convert()直接返回字节[]。
解决方案:IronPDF返回一个具有多个输出选项的 PdfDocument 对象:
var pdf = renderer.RenderHtmlAsPdf(html);
byte[] bytes = pdf.BinaryData; // Get bytes
pdf.SaveAs("output.pdf"); // Or save directlyvar pdf = renderer.RenderHtmlAsPdf(html);
byte[] bytes = pdf.BinaryData; // Get bytes
pdf.SaveAs("output.pdf"); // Or save directly问题 4:页眉/页脚占位符语法
Haukcode.DinkToPdf:使用方括号语法,如<代码>[页面]</代码和<代码>[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}"
};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" .记录当前的<代码>全局设置</代码和<代码>对象设置</代码配置。 确定任何可以删除的本地库加载代码。
代码更新任务
1.删除 DinkToPdf NuGet 软件包 2.安装 IronPdf NuGet 软件包 3.将名称空间导入从 DinkToPdf 更新为 IronPdf 4.将<代码>同步转换器</代码替换为 ChromePdfRenderer 5.将<代码>HtmlToPdfDocument</代码模式转换为直接方法调用 6.将<代码>全局设置</代码转换为 RenderingOptions 7.将<代码>对象设置</代码转换为 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 版本兼容。






