如何用 C# 从 TuesPechkin 迁移到 IronPDF
TuesPechkin 是 wkhtmltopdf 库的线程安全封装程序,多年来一直帮助 .NET 开发人员将 HTML 转换为 PDF。 然而,wkhtmltopdf 的底层技术最后一次更新是在 2015 年,并于 2022 年 12 月正式废弃。这就造成了开发团队无法再忽视的关键安全性、稳定性和渲染限制。
本指南提供了从TuesPechkin到IronPDF的完整迁移路径,为评估这一过渡的专业 .NET 开发人员提供了分步说明、代码比较和实用示例。
为什么现在就从TuesPechkin迁移
对于具有安全意识的开发团队来说,从TuesPechkin迁移的决定不再是可有可无的。 wkhtmltopdf 库的底层存在严重的未修补漏洞,这些漏洞将永远无法修复。
关键安全漏洞:CVE-2022-35583.
| 属性 | 价值 |
|---|---|
| CVE ID | CVE-2022-35583 |
| 严重性 | CRITICAL (9.8/10) |
| 攻击向量 | 网络 |
| 状态 | 永不打补丁 |
| 受影响 | 所有TuesPechkin版本 |
wkhtmltopdf 维护者明确表示他们不会修复安全漏洞。 每个使用TuesPechkin的应用程序都会长期受到服务器端请求伪造 (SSRF) 攻击。
攻击如何工作
在处理用户提供的 HTML 时,攻击者可以注入恶意内容:
<iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe>
<img src="http://internal-admin-panel:8080/api/users?export=all" />
<iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe>
<img src="http://internal-admin-panel:8080/api/users?export=all" />
这使得攻击者可以访问 AWS/Azure/GCP 元数据端点、窃取内部 API 数据、对内部网络进行端口扫描并外泄敏感配置。
技术危机
TuesPechkin 包装了 wkhtmltopdf,它使用 Qt WebKit 4.8--前 Chrome 时代的古老技术。 这意味着:
- 不支持 Flexbox
- 不支持 CSS 网格
- JavaScript 执行中断
- 不支持 ES6+
稳定危机
即使使用了官方宣传的 ThreadSafeConverter,TuesPechkin 在高负载下仍然会崩溃:
// ❌TuesPechkin- "ThreadSafeConverter" still crashes
var converter = new TuesPechkin.ThreadSafeConverter(
new TuesPechkin.RemotingToolset<PechkinBindings>());
// Under high load, you'll see:
// System.AccessViolationException: Attempted to read or write protected memory
// Process terminated unexpectedly
// Converter hangs indefinitely
// ❌TuesPechkin- "ThreadSafeConverter" still crashes
var converter = new TuesPechkin.ThreadSafeConverter(
new TuesPechkin.RemotingToolset<PechkinBindings>());
// Under high load, you'll see:
// System.AccessViolationException: Attempted to read or write protected memory
// Process terminated unexpectedly
// Converter hangs indefinitely
' ❌TuesPechkin- "ThreadSafeConverter" still crashes
Dim converter = New TuesPechkin.ThreadSafeConverter(
New TuesPechkin.RemotingToolset(Of PechkinBindings)())
' Under high load, you'll see:
' System.AccessViolationException: Attempted to read or write protected memory
' Process terminated unexpectedly
' Converter hangs indefinitely
IronPDF与 TuesPechkin:功能对比
了解架构差异有助于技术决策者评估迁移投资:
| 特征 | TuesPechkin | IronPDF |
|---|---|---|
| 许可 | 免费(MIT 许可) | 商业翻译 |
| 线程安全 | 需要人工管理 | 本地支持 |
| 货币 | 有局限性,在负载情况下可能会崩溃 | 稳健,可处理高并发 |
| 开发 | 不活跃,最后更新时间为 2015 年 | 积极、持续的改进 |
| 易用性 | 复杂的设置 | 方便用户使用的指南 |
| 文档 | 基本的 | 包含大量示例 |
| 安全性 | ❌ 关键 CVE | ✅ 无已知漏洞 |
| HTML 到 PDF | ⚠️ 过时的 WebKit | ✅ 现代 Chromium |
| CSS3代码 | ❌ 部分 | ✅ 已支持 |
| Flexbox/网格 | ❌ 不支持 | ✅ 已支持 |
| JavaScript语言 | ⚠️ 不可靠 | ✅ 完全 ES6+ |
| PDF 操作 | ❌ 不可用 | ✅ 全文 |
| 数字签名 | ❌ 不可用 | ✅ 全文 |
| PDF/A合规性 | ❌ 不可用 | ✅ 全文 |
| 表格填写 | ❌ 不可用 | ✅ 全文 |
| 水印。 | ❌ 不可用 | ✅ 全文 |
| 合并/拆分 | ❌ 不可用 | ✅ 全文 |
快速入门:将IronPDF移植到 TuesPechkin.
迁移工作可以通过以下基本步骤立即开始。
步骤 1:替换 NuGet 软件包
删除所有TuesPechkin软件包:
# RemoveTuesPechkinand all related packages
dotnet remove package TuesPechkin
dotnet remove package TuesPechkin.Wkhtmltox.Win64
dotnet remove package TuesPechkin.Wkhtmltox.Win32
# RemoveTuesPechkinand all related packages
dotnet remove package TuesPechkin
dotnet remove package TuesPechkin.Wkhtmltox.Win64
dotnet remove package TuesPechkin.Wkhtmltox.Win32
安装 IronPDF:
# Install IronPDF
dotnet add package IronPdf
# Install IronPDF
dotnet add package IronPdf
步骤 2:删除本地二进制文件
从您的项目中删除这些文件和文件夹:
wkhtmltox.dllwkhtmltopdf.exe- 任何
wkhtmlto*文件 TuesPechkin.Wkhtmltox文件夹
步骤 3:更新命名空间
用IronPDF命名空间替换TuesPechkin命名空间:
// Before (TuesPechkin)
using TuesPechkin;
using TuesPechkin.Wkhtmltox.Win64;
// After (IronPDF)
using IronPdf;
// Before (TuesPechkin)
using TuesPechkin;
using TuesPechkin.Wkhtmltox.Win64;
// After (IronPDF)
using IronPdf;
' Before (TuesPechkin)
Imports TuesPechkin
Imports TuesPechkin.Wkhtmltox.Win64
' After (IronPDF)
Imports IronPdf
步骤 4:初始化许可证
在应用程序启动时添加许可证初始化:
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
代码迁移示例
将HTML转换为PDF
最常见的使用案例展示了这些 .NET PDF 库之间的复杂性差异。
TuesPechkin 方法:
// NuGet: Install-Package TuesPechkin
using TuesPechkin;
using System.IO;
class Program
{
static void Main()
{
var converter = new StandardConverter(
new RemotingToolset<PdfToolset>(
new Win64EmbeddedDeployment(
new TempFolderDeployment())));
string html = "<html><body><h1>Hello World</h1></body></html>";
byte[] pdfBytes = converter.Convert(new HtmlToPdfDocument
{
Objects = { new ObjectSettings { HtmlText = html } }
});
File.WriteAllBytes("output.pdf", pdfBytes);
}
}
// NuGet: Install-Package TuesPechkin
using TuesPechkin;
using System.IO;
class Program
{
static void Main()
{
var converter = new StandardConverter(
new RemotingToolset<PdfToolset>(
new Win64EmbeddedDeployment(
new TempFolderDeployment())));
string html = "<html><body><h1>Hello World</h1></body></html>";
byte[] pdfBytes = converter.Convert(new HtmlToPdfDocument
{
Objects = { new ObjectSettings { HtmlText = html } }
});
File.WriteAllBytes("output.pdf", pdfBytes);
}
}
Imports TuesPechkin
Imports System.IO
Class Program
Shared Sub Main()
Dim converter = New StandardConverter(
New RemotingToolset(Of PdfToolset)(
New Win64EmbeddedDeployment(
New TempFolderDeployment())))
Dim html As String = "<html><body><h1>Hello World</h1></body></html>"
Dim pdfBytes As Byte() = converter.Convert(New HtmlToPdfDocument With {
.Objects = {New ObjectSettings With {.HtmlText = html}}
})
File.WriteAllBytes("output.pdf", pdfBytes)
End Sub
End Class
IronPDF 方法:
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string html = "<html><body><h1>Hello World</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string html = "<html><body><h1>Hello World</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
}
Imports IronPdf
Imports System
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim html As String = "<html><body><h1>Hello World</h1></body></html>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
End Sub
End Class
TuesPechkin 版本需要创建一个具有复杂初始化链的 StandardConverter:RemotingToolset、Win64EmbeddedDeployment 和 TempFolderDeployment。 您还必须手动将字节写入文件。
IronPDF 完全消除了这一仪式。 创建 ChromePdfRenderer,渲染 HTML,并保存。 代码是自文档化的,不需要了解部署工具集或特定平台的二进制管理。
有关 HTML 转 PDF 的高级应用场景,请参阅 HTML 转 PDF 指南。
将 URL 转换为 PDF
URL 到 PDF 的转换也存在类似的复杂性差异。
TuesPechkin 方法:
// NuGet: Install-Package TuesPechkin
using TuesPechkin;
using System.IO;
class Program
{
static void Main()
{
var converter = new StandardConverter(
new RemotingToolset<PdfToolset>(
new Win64EmbeddedDeployment(
new TempFolderDeployment())));
byte[] pdfBytes = converter.Convert(new HtmlToPdfDocument
{
Objects = {
new ObjectSettings {
PageUrl = "https://www.example.com"
}
}
});
File.WriteAllBytes("webpage.pdf", pdfBytes);
}
}
// NuGet: Install-Package TuesPechkin
using TuesPechkin;
using System.IO;
class Program
{
static void Main()
{
var converter = new StandardConverter(
new RemotingToolset<PdfToolset>(
new Win64EmbeddedDeployment(
new TempFolderDeployment())));
byte[] pdfBytes = converter.Convert(new HtmlToPdfDocument
{
Objects = {
new ObjectSettings {
PageUrl = "https://www.example.com"
}
}
});
File.WriteAllBytes("webpage.pdf", pdfBytes);
}
}
Imports TuesPechkin
Imports System.IO
Class Program
Shared Sub Main()
Dim converter = New StandardConverter(
New RemotingToolset(Of PdfToolset)(
New Win64EmbeddedDeployment(
New TempFolderDeployment())))
Dim pdfBytes As Byte() = converter.Convert(New HtmlToPdfDocument With {
.Objects = {
New ObjectSettings With {
.PageUrl = "https://www.example.com"
}
}
})
File.WriteAllBytes("webpage.pdf", pdfBytes)
End Sub
End Class
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
TuesPechkin 使用 ObjectSettings.PageUrl 嵌套在 HtmlToPdfDocument 中。IronPDF提供了一个专门的 RenderUrlAsPdf 方法,可以清晰地表达意图。
请浏览 URL to PDF 文档,了解身份验证和自定义页眉选项。
自定义渲染设置
页面方向、纸张大小和页边距要求采用不同的配置方法。
TuesPechkin 方法:
// NuGet: Install-Package TuesPechkin
using TuesPechkin;
using System.IO;
class Program
{
static void Main()
{
var converter = new StandardConverter(
new RemotingToolset<PdfToolset>(
new Win64EmbeddedDeployment(
new TempFolderDeployment())));
string html = "<html><body><h1>Custom PDF</h1></body></html>";
var document = new HtmlToPdfDocument
{
GlobalSettings = {
Orientation = GlobalSettings.PdfOrientation.Landscape,
PaperSize = GlobalSettings.PdfPaperSize.A4,
Margins = new MarginSettings { Unit = Unit.Millimeters, Top = 10, Bottom = 10 }
},
Objects = {
new ObjectSettings { HtmlText = html }
}
};
byte[] pdfBytes = converter.Convert(document);
File.WriteAllBytes("custom.pdf", pdfBytes);
}
}
// NuGet: Install-Package TuesPechkin
using TuesPechkin;
using System.IO;
class Program
{
static void Main()
{
var converter = new StandardConverter(
new RemotingToolset<PdfToolset>(
new Win64EmbeddedDeployment(
new TempFolderDeployment())));
string html = "<html><body><h1>Custom PDF</h1></body></html>";
var document = new HtmlToPdfDocument
{
GlobalSettings = {
Orientation = GlobalSettings.PdfOrientation.Landscape,
PaperSize = GlobalSettings.PdfPaperSize.A4,
Margins = new MarginSettings { Unit = Unit.Millimeters, Top = 10, Bottom = 10 }
},
Objects = {
new ObjectSettings { HtmlText = html }
}
};
byte[] pdfBytes = converter.Convert(document);
File.WriteAllBytes("custom.pdf", pdfBytes);
}
}
Imports TuesPechkin
Imports System.IO
Module Program
Sub Main()
Dim converter = New StandardConverter(
New RemotingToolset(Of PdfToolset)(
New Win64EmbeddedDeployment(
New TempFolderDeployment())))
Dim html As String = "<html><body><h1>Custom PDF</h1></body></html>"
Dim document = New HtmlToPdfDocument With {
.GlobalSettings = New GlobalSettings With {
.Orientation = GlobalSettings.PdfOrientation.Landscape,
.PaperSize = GlobalSettings.PdfPaperSize.A4,
.Margins = New MarginSettings With {.Unit = Unit.Millimeters, .Top = 10, .Bottom = 10}
},
.Objects = {
New ObjectSettings With {.HtmlText = html}
}
}
Dim pdfBytes As Byte() = converter.Convert(document)
File.WriteAllBytes("custom.pdf", pdfBytes)
End Sub
End Module
IronPDF 方法:
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Engines.Chrome;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
string html = "<html><body><h1>Custom PDF</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("custom.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Engines.Chrome;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
string html = "<html><body><h1>Custom PDF</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("custom.pdf");
}
}
Imports IronPdf
Imports IronPdf.Engines.Chrome
Imports System
Module Program
Sub Main()
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
renderer.RenderingOptions.MarginTop = 10
renderer.RenderingOptions.MarginBottom = 10
Dim html As String = "<html><body><h1>Custom PDF</h1></body></html>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("custom.pdf")
End Sub
End Module
TuesPechkin 将设置分为 GlobalSettings(文档范围选项)和 ObjectSettings(内容)。IronPDF将所有内容整合到 RenderingOptions 中,并使用清晰、易于发现的属性名称。
TuesPechkinAPI 到IronPDF映射参考
这种映射通过显示直接的 API 对应关系来加速迁移:
| TuesPechkin | IronPDF |
|---|---|
StandardConverter |
ChromePdfRenderer |
ThreadSafeConverter |
ChromePdfRenderer |
HtmlToPdfDocument |
方法参数 |
GlobalSettings |
RenderingOptions |
ObjectSettings.HtmlText |
RenderHtmlAsPdf(html) |
ObjectSettings.PageUrl |
RenderUrlAsPdf(url) |
GlobalSettings.PaperSize |
RenderingOptions.PaperSize |
GlobalSettings.Orientation |
RenderingOptions.PaperOrientation |
MarginSettings |
MarginTop,MarginBottom,等等。 |
[page]占位符 |
{page}占位符 |
[toPage]占位符 |
{total-pages}占位符 |
RemotingToolset |
不需要 |
Win64EmbeddedDeployment |
不需要 |
TempFolderDeployment |
不需要 |
常见迁移问题和解决方案
问题 1:复杂的初始化代码
问题:TuesPechkin需要复杂的转换器设置和部署工具集。
解决方案:IronPDF 很简单:
// Before (TuesPechkin)
var converter = new StandardConverter(
new RemotingToolset<PdfToolset>(
new Win64EmbeddedDeployment(
new TempFolderDeployment())));
// After (IronPDF)
var renderer = new ChromePdfRenderer();
// That's it!
// Before (TuesPechkin)
var converter = new StandardConverter(
new RemotingToolset<PdfToolset>(
new Win64EmbeddedDeployment(
new TempFolderDeployment())));
// After (IronPDF)
var renderer = new ChromePdfRenderer();
// That's it!
' Before (TuesPechkin)
Dim converter = New StandardConverter(
New RemotingToolset(Of PdfToolset)(
New Win64EmbeddedDeployment(
New TempFolderDeployment())))
' After (IronPDF)
Dim renderer = New ChromePdfRenderer()
' That's it!
问题 2:线程安全崩溃
问题:TuesPechkin的 ThreadSafeConverter 在高负载下仍然崩溃,并出现 AccessViolationException。
解决方案:IronPDF具有本地线程安全功能,无需特殊配置:
//IronPDFis inherently thread-safe
var renderer = new ChromePdfRenderer();
// Use from any thread without crashes
//IronPDFis inherently thread-safe
var renderer = new ChromePdfRenderer();
// Use from any thread without crashes
'IronPDF is inherently thread-safe
Dim renderer As New ChromePdfRenderer()
' Use from any thread without crashes
问题 3:页码占位符语法
问题:TuesPechkin使用 [page] 和 [toPage] 占位符。
解决方案:更新IronPDF的占位符语法:
// Before (TuesPechkin)
"Page [page] of [toPage]"
// After (IronPDF)
"Page {page} of {total-pages}"
// Before (TuesPechkin)
"Page [page] of [toPage]"
// After (IronPDF)
"Page {page} of {total-pages}"
问题 4:CSS 布局已损坏
问题:由于 wkhtmltopdf 使用 Qt WebKit 4.8,因此 Flexbox 和网格布局无法在TuesPechkin中使用。
解决方案:使用IronPDF适当的现代 CSS:
// Remove table-based workarounds, use modern CSS
var html = @"
<div style='display: flex; justify-content: space-between;'>
<div>Left</div>
<div>Right</div>
</div>";
var pdf = renderer.RenderHtmlAsPdf(html);
// Works correctly with Chromium!
// Remove table-based workarounds, use modern CSS
var html = @"
<div style='display: flex; justify-content: space-between;'>
<div>Left</div>
<div>Right</div>
</div>";
var pdf = renderer.RenderHtmlAsPdf(html);
// Works correctly with Chromium!
' Remove table-based workarounds, use modern CSS
Dim html As String = "
<div style='display: flex; justify-content: space-between;'>
<div>Left</div>
<div>Right</div>
</div>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
' Works correctly with Chromium!
第 5 期:本地二进制管理
问题:TuesPechkin需要特定平台的 wkhtmltopdf 二进制文件和路径配置。
解决方案:IronPDF 通过 NuGet 处理所有依赖关系,无需管理本地二进制文件:
# Just install the package
dotnet add package IronPdf
# No wkhtmltopdf binaries needed
# Just install the package
dotnet add package IronPdf
# No wkhtmltopdf binaries needed
TuesPechkin迁移清单
迁移前任务
审核您的代码库,确定所有TuesPechkin的使用情况:
grep -r "using TuesPechkin" --include="*.cs" .
grep -r "ThreadSafeConverter\|RemotingToolset" --include="*.cs" .
grep -r "using TuesPechkin" --include="*.cs" .
grep -r "ThreadSafeConverter\|RemotingToolset" --include="*.cs" .
记录当前 GlobalSettings 配置(纸张尺寸、方向、边距)。 文档 ObjectSettings 配置(HTML 内容、URL)。 确定转换的页眉/页脚实现。 查找所有 wkhtmltopdf 二进制文件以进行删除。
代码更新任务
1.删除TuesPechkinNuGet 软件包 2.删除本地 wkhtmltopdf 二进制文件 3.安装IronPDFNuGet 软件包
- 使用语句从
TuesPechkin更新到IronPdf5.在启动时添加许可证密钥初始化 - 将转换器替换为
ChromePdfRenderer - 将
GlobalSettings转换为RenderingOptions - 将
ObjectSettings转换为方法参数 9.将边距配置更新为单个属性 - 将页眉/页脚语法更新为基于 HTML 的
HtmlHeaderFooter - 修复页面占位符语法(
[page]→{page}) 12.删除所有部署/工具集代码
迁移后测试
迁移后,验证这些方面:
- 运行所有单元测试
- 测试线程安全场景(IronPDF 可处理多线程而不会崩溃)
- 比较 PDF 输出质量(Chromium 的渲染更准确)
- 验证 CSS 呈现(Flexbox 和 Grid 现在可以使用)
- 测试 JavaScript 的执行(现在支持 ES6+)
- 测试页眉/页脚渲染
- 性能测试批量操作
- 安全扫描以验证没有 wkhtmltopdf 二进制文件残留
迁移到IronPDF的主要优势
从TuesPechkin迁移到IronPDF有几个关键优势:
安全性:CVE-2022-35583和其他 wkhtmltopdf 漏洞已消除。IronPDF的 Chromium 引擎会定期接受安全更新。
原生线程安全:不再需要复杂的配置。 不再出现 AccessViolationException 在负载下崩溃的情况。IronPDF自动处理并发性。
现代渲染引擎:完全支持 CSS3、Flexbox、Grid 和 ES6+ JavaScript。 您的 PDF 将与现代浏览器中显示的内容完全一致。
简化部署:无需管理特定于平台的二进制文件。 没有 RemotingToolset、Win64EmbeddedDeployment 或 TempFolderDeployment 仪式。 安装 NuGet 软件包即可。
积极开发:随着 .NET 10 和 C# 14 的普及,IronPDF 将持续更新,确保与当前和未来的 .NET 版本兼容。
扩展功能:TuesPechkin仅将 HTML 转换为 PDF。IronPDF增加了 PDF 操作、数字签名、PDF/A 合规性、表格填充、水印和合并/拆分操作。

