如何使用C#将RTF转换为PDF
为什么要从 NReco PDF 生成器迁移到 IronPDF?
NReco PDF 生成器的关键安全问题
NReco PDF Generator 包装了 wkhtmltopdf 二进制文件,继承了其已知的安全漏洞。 wkhtmltopdf 项目的最后一个稳定版本是 0.12.6 (2020年6月),其上游仓库于 2023年1月2日归档,因此不会有任何补丁发布:
- CVE-2020-21365: 目录遍历/ Crafted HTML 的本地文件读取 (同源策略弱点)
- CVE-2022-35583: 通过在 0.12.6 中注入的
<iframe>进行服务器端请求伪造 (SSRF) (CVSS 9.8)
NReco PDF 生成器的其他限制
-
大规模许可摩擦: 对于非SaaS的单服务器生产部署免费; SaaS、多服务器或再分发场景需要从nrecosite.com购买199美元的企业源代码包。
-
弃用的渲染引擎: WebKit Qt (约2012年) 仅支持有限的CSS3/JS:
- 无 CSS 网格或 Flexbox
- 无现代 JavaScript(ES6+)
- 网页字体支持不佳
- 无 CSS 变量或自定义属性
-
外部二进制依赖: 需要根据平台管理 wkhtmltopdf 二进制文件 (
wkhtmltopdf.exe,wkhtmltox.dll)。 - 维护停滞: NReco.PdfGenerator 1.2.1 于2023年1月8日发布,自此后在nuget.org上未再有任何发布; 底层 wkhtmltopdf 引擎不再更新。
5.异步支持有限:同步 API 会阻塞 Web 应用程序中的线程。
NReco PDF 生成器与IronPDF的比较
| 方面 | NReco PDF 生成器 | IronPDF |
|---|---|---|
| 渲染引擎 | WebKit Qt (2012) | Chromium (当前) |
| 安全性 | 多个未修补的 CVEs (例如 CVE-2020-21365, CVE-2022-35583); 引擎于2023年1月2日归档 | 主动安全更新 |
| CSS 支持 | CSS2.1, 有限 CSS3 | 完全 CSS3、网格、Flexbox |
| JavaScript | 基本 ES5 | 完整的 ES6+、async/await |
| 依赖关系 | 外部 wkhtmltopdf 二进制文件 | 自成一体 |
| 异步支持 | 仅同步 | 完整的Async/Await |
| 网络字体 | 有限的 | 完整的谷歌字体,@font-face |
| 许可 | 非SaaS单服务器免费; SaaS/多服务器199美元企业包 | 透明的商业定价 |
| 免费级别 | 非SaaS单服务器许可证下免费 | 试用不需要水印 |
开始之前
前提条件
- .NET 环境: .NET Framework 4.6.2+ 或 .NET Core 3.1+ / .NET 5/6/7/8/9+
- NuGet 访问权限:能够安装 NuGet 包
- IronPDF 许可证:请从ironpdf.com获取您的许可证密钥。
NuGet 软件包变更
# Remove NReco.PdfGenerator
dotnet remove package NReco.PdfGenerator
# Install IronPDF
dotnet add package IronPdf
# Remove NReco.PdfGenerator
dotnet remove package NReco.PdfGenerator
# Install IronPDF
dotnet add package IronPdf
同时从您的部署中删除 wkhtmltopdf 二进制文件:
- 从项目中删除
wkhtmltopdf.exe,wkhtmltox.dll - 删除任何 wkhtmltopdf 安装脚本
- 删除特定平台的二进制文件夹
许可配置
// Add at application startup (Program.cs or Startup.cs)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Add at application startup (Program.cs or Startup.cs)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
' Add at application startup (Program.vb or Startup.vb)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
确定 NReco PDF 生成器的用途
# Find all NReco.PdfGenerator references
grep -r "NReco.PdfGenerator\|HtmlToPdfConverter\|GeneratePdf" --include="*.cs" .
# Find all NReco.PdfGenerator references
grep -r "NReco.PdfGenerator\|HtmlToPdfConverter\|GeneratePdf" --include="*.cs" .
完整的 API 参考
核心类映射
| NReco PDF 生成器 | IronPDF |
|---|---|
HtmlToPdfConverter |
ChromePdfRenderer |
PageMargins |
个别边距属性 |
PageOrientation |
PdfPaperOrientation |
PageSize |
PdfPaperSize |
渲染方法映射
| NReco PDF 生成器 | IronPDF |
|---|---|
GeneratePdf(html) |
RenderHtmlAsPdf(html) |
GeneratePdfFromFile(url, output) |
RenderUrlAsPdf(url) |
GeneratePdfFromFile(htmlPath, output) |
RenderHtmlFileAsPdf(path) |
| (不支持异步) | RenderHtmlAsPdfAsync(html) |
| (不支持异步) | RenderUrlAsPdfAsync(url) |
页面配置映射
| NReco PDF 生成器 | IronPDF |
|---|---|
PageWidth = 210 |
RenderingOptions.PaperSize = PdfPaperSize.A4 |
PageHeight = 297 |
RenderingOptions.SetCustomPaperSizeinMilimeters(w, h) |
Orientation = PageOrientation.Landscape |
RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape |
Size = PageSize.A4 |
RenderingOptions.PaperSize = PdfPaperSize.A4 |
边距映射
| NReco PDF 生成器 | IronPDF |
|---|---|
Margins.Top = 10 |
RenderingOptions.MarginTop = 10 |
Margins.Bottom = 10 |
RenderingOptions.MarginBottom = 10 |
Margins.Left = 10 |
RenderingOptions.MarginLeft = 10 |
Margins.Right = 10 |
RenderingOptions.MarginRight = 10 |
new PageMargins { ... } |
个别属性 |
页眉/页脚占位符映射
| NReco PDF 生成器 (wkhtmltopdf) | IronPDF |
|---|---|
[page] |
{page} |
[topage] |
{total-pages} |
[date] |
{date} |
[time] |
{time} |
[title] |
{html-title} |
输出处理映射
| NReco PDF 生成器 | IronPDF |
|---|---|
byte[] pdfBytes = GeneratePdf(html) |
PdfDocument pdf = RenderHtmlAsPdf(html) |
File.WriteAllBytes(path, bytes) |
pdf.SaveAs(path) |
return pdfBytes |
return pdf.BinaryData |
new MemoryStream(pdfBytes) |
new MemoryStream(pdf.BinaryData) |
代码迁移示例
示例 1:将基本 HTML 转换为 PDF.
之前(NReco PDF 生成器):
// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;
class Program
{
static void Main()
{
var htmlToPdf = new HtmlToPdfConverter();
var htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
var pdfBytes = htmlToPdf.GeneratePdf(htmlContent);
File.WriteAllBytes("output.pdf", pdfBytes);
}
}
// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;
class Program
{
static void Main()
{
var htmlToPdf = new HtmlToPdfConverter();
var htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
var pdfBytes = htmlToPdf.GeneratePdf(htmlContent);
File.WriteAllBytes("output.pdf", pdfBytes);
}
}
Imports NReco.PdfGenerator
Imports System.IO
Class Program
Shared Sub Main()
Dim htmlToPdf = New HtmlToPdfConverter()
Dim htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>"
Dim pdfBytes = htmlToPdf.GeneratePdf(htmlContent)
File.WriteAllBytes("output.pdf", pdfBytes)
End Sub
End Class
After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using System.IO;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("output.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System.IO;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("output.pdf");
}
}
Imports IronPdf
Imports System.IO
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>"
Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs("output.pdf")
End Sub
End Class
基本区别在于返回类型和保存模式。NReco PDF 生成器的File.WriteAllBytes()手动将其写入磁盘。IronPDF的PdfDocument对象。
这种面向对象的方法还有其他好处:您可以在保存之前对 PDF 进行操作(添加水印、合并文档、添加安全性)。 如果您需要原始字节以与现有代码兼容,请使用pdf.BinaryData。 有关其他渲染选项,请参阅 HTML to PDF 文档。
示例 2:带边距的自定义页面大小
之前(NReco PDF 生成器):
// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;
class Program
{
static void Main()
{
var htmlToPdf = new HtmlToPdfConverter();
htmlToPdf.PageWidth = 210;
htmlToPdf.PageHeight = 297;
htmlToPdf.Margins = new PageMargins { Top = 10, Bottom = 10, Left = 10, Right = 10 };
var htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>";
var pdfBytes = htmlToPdf.GeneratePdf(htmlContent);
File.WriteAllBytes("custom-size.pdf", pdfBytes);
}
}
// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;
class Program
{
static void Main()
{
var htmlToPdf = new HtmlToPdfConverter();
htmlToPdf.PageWidth = 210;
htmlToPdf.PageHeight = 297;
htmlToPdf.Margins = new PageMargins { Top = 10, Bottom = 10, Left = 10, Right = 10 };
var htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>";
var pdfBytes = htmlToPdf.GeneratePdf(htmlContent);
File.WriteAllBytes("custom-size.pdf", pdfBytes);
}
}
Imports NReco.PdfGenerator
Imports System.IO
Class Program
Shared Sub Main()
Dim htmlToPdf = New HtmlToPdfConverter()
htmlToPdf.PageWidth = 210
htmlToPdf.PageHeight = 297
htmlToPdf.Margins = New PageMargins With {.Top = 10, .Bottom = 10, .Left = 10, .Right = 10}
Dim htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>"
Dim pdfBytes = htmlToPdf.GeneratePdf(htmlContent)
File.WriteAllBytes("custom-size.pdf", pdfBytes)
End Sub
End Class
After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
var htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>";
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("custom-size.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
var htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>";
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("custom-size.pdf");
}
}
Imports IronPdf
Imports IronPdf.Rendering
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
renderer.RenderingOptions.MarginTop = 10
renderer.RenderingOptions.MarginBottom = 10
renderer.RenderingOptions.MarginLeft = 10
renderer.RenderingOptions.MarginRight = 10
Dim htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>"
Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs("custom-size.pdf")
End Sub
End Class
NReco PDF Generator 使用数值维度 (PageWidth = 210, PageHeight = 297) 和一个PageMargins对象。IronPDF使用PdfPaperSize枚举(包括标准尺寸如 A4、Letter、Legal)和RenderingOptions对象上的单独边距属性。
关键的迁移变化:
PageHeight→RenderingOptions.PaperSize = PdfPaperSize.A4new PageMargins { Top = 10, ... }→ Individual properties:RenderingOptions.MarginTop = 10
对于未在枚举中涵盖的自定义纸张尺寸,请使用RenderingOptions.SetCustomPaperSizeinMilimeters(width, height)。 了解页面配置选项的更多信息。
示例 3:URL 到 PDF 的转换
之前(NReco PDF 生成器):
// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;
class Program
{
static void Main()
{
var htmlToPdf = new HtmlToPdfConverter();
var pdfBytes = htmlToPdf.GeneratePdfFromFile("https://www.example.com", null);
File.WriteAllBytes("webpage.pdf", pdfBytes);
}
}
// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;
class Program
{
static void Main()
{
var htmlToPdf = new HtmlToPdfConverter();
var pdfBytes = htmlToPdf.GeneratePdfFromFile("https://www.example.com", null);
File.WriteAllBytes("webpage.pdf", pdfBytes);
}
}
Imports NReco.PdfGenerator
Imports System.IO
Class Program
Shared Sub Main()
Dim htmlToPdf As New HtmlToPdfConverter()
Dim pdfBytes As Byte() = htmlToPdf.GeneratePdfFromFile("https://www.example.com", Nothing)
File.WriteAllBytes("webpage.pdf", pdfBytes)
End Sub
End Class
After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
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;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("webpage.pdf");
}
}
Imports IronPdf
Class Program
Shared Sub Main()
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("webpage.pdf")
End Sub
End Class
NReco PDF Generator 使用令人困惑的GeneratePdfFromFile()方法来处理本地文件和 URL,第二个参数是可为空的。IronPDF提供专用方法: RenderUrlAsPdf()用于 URL,RenderHtmlFileAsPdf()用于本地 HTML 文件。
IronPDF 的方法更简洁且更直观。对于异步 Web 应用程序,请使用await renderer.RenderUrlAsPdfAsync(url)以避免阻塞线程——这是NReco PDF 生成器无法做到的。
关键迁移说明
缩放值转换
NReco PDF Generator 使用浮点数值(0.0-2.0),而IronPDF使用百分比整数:
// NReco PDF Generator: Zoom = 0.9f (90%)
// IronPDF: Zoom = 90
// Conversion formula:
int ironPdfZoom = (int)(nrecoZoom * 100);
// NReco PDF Generator: Zoom = 0.9f (90%)
// IronPDF: Zoom = 90
// Conversion formula:
int ironPdfZoom = (int)(nrecoZoom * 100);
' NReco PDF Generator: Zoom = 0.9F (90%)
' IronPDF: Zoom = 90
' Conversion formula:
Dim ironPdfZoom As Integer = CInt(nrecoZoom * 100)
占位符语法更新
必须更新所有页眉/页脚占位符:
| NReco PDF 生成器 | IronPDF |
|---|---|
[page] |
{page} |
[topage] |
{total-pages} |
[date] |
{date} |
[title] |
{html-title} |
// NReco PDF Generator:
converter.PageFooterHtml = "<div>Page [page] of [topage]</div>";
// IronPDF:
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div>Page {page} of {total-pages}</div>",
MaxHeight = 20
};
// NReco PDF Generator:
converter.PageFooterHtml = "<div>Page [page] of [topage]</div>";
// IronPDF:
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div>Page {page} of {total-pages}</div>",
MaxHeight = 20
};
Imports NReco.PdfGenerator
Imports IronPdf
' NReco PDF Generator:
converter.PageFooterHtml = "<div>Page [page] of [topage]</div>"
' IronPDF:
renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
.HtmlFragment = "<div>Page {page} of {total-pages}</div>",
.MaxHeight = 20
}
返回类型更改
NReco PDF Generator 直接返回byte[];IronPDF返回PdfDocument:
//NReco PDF 生成器pattern:
byte[] pdfBytes = converter.GeneratePdf(html);
File.WriteAllBytes("output.pdf", pdfBytes);
//IronPDFpattern:
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
// Or if you need bytes:
byte[] pdfBytes = renderer.RenderHtmlAsPdf(html).BinaryData;
//NReco PDF 生成器pattern:
byte[] pdfBytes = converter.GeneratePdf(html);
File.WriteAllBytes("output.pdf", pdfBytes);
//IronPDFpattern:
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
// Or if you need bytes:
byte[] pdfBytes = renderer.RenderHtmlAsPdf(html).BinaryData;
Imports System.IO
' NReco PDF 生成器pattern:
Dim pdfBytes As Byte() = converter.GeneratePdf(html)
File.WriteAllBytes("output.pdf", pdfBytes)
' IronPDFpattern:
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
' Or if you need bytes:
Dim pdfBytes As Byte() = renderer.RenderHtmlAsPdf(html).BinaryData
线程安全和可重用性
NReco PDF 生成器通常每次调用都会创建一个新的转换器。IronPDF的ChromePdfRenderer是线程安全的并且可以重用:
//NReco PDF 生成器pattern (creates new each time):
public byte[] Generate(string html)
{
var converter = new HtmlToPdfConverter();
return converter.GeneratePdf(html);
}
//IronPDFpattern (reuse renderer, thread-safe):
private readonly ChromePdfRenderer _renderer = new ChromePdfRenderer();
public byte[] Generate(string html)
{
return _renderer.RenderHtmlAsPdf(html).BinaryData;
}
//NReco PDF 生成器pattern (creates new each time):
public byte[] Generate(string html)
{
var converter = new HtmlToPdfConverter();
return converter.GeneratePdf(html);
}
//IronPDFpattern (reuse renderer, thread-safe):
private readonly ChromePdfRenderer _renderer = new ChromePdfRenderer();
public byte[] Generate(string html)
{
return _renderer.RenderHtmlAsPdf(html).BinaryData;
}
Imports NReco.PdfGenerator
Imports IronPdf
' NReco PDF 生成器pattern (creates new each time):
Public Function Generate(html As String) As Byte()
Dim converter As New HtmlToPdfConverter()
Return converter.GeneratePdf(html)
End Function
' IronPDFpattern (reuse renderer, thread-safe):
Private ReadOnly _renderer As New ChromePdfRenderer()
Public Function Generate(html As String) As Byte()
Return _renderer.RenderHtmlAsPdf(html).BinaryData
End Function
异步支持(新功能)
IronPDF 支持NReco PDF 生成器无法提供的Async/Await模式:
// NReco PDF Generator: No async support available
// IronPDF: Full async support
public async Task<byte[]> GenerateAsync(string html)
{
var pdf = await _renderer.RenderHtmlAsPdfAsync(html);
return pdf.BinaryData;
}
// NReco PDF Generator: No async support available
// IronPDF: Full async support
public async Task<byte[]> GenerateAsync(string html)
{
var pdf = await _renderer.RenderHtmlAsPdfAsync(html);
return pdf.BinaryData;
}
Imports System.Threading.Tasks
' NReco PDF Generator: No async support available
' IronPDF: Full async support
Public Async Function GenerateAsync(html As String) As Task(Of Byte())
Dim pdf = Await _renderer.RenderHtmlAsPdfAsync(html)
Return pdf.BinaryData
End Function
故障排除
问题 1:HtmlToPdfConverter 未找到
问题:IronPDF中不存在HtmlToPdfConverter类。
解决方案: 使用ChromePdfRenderer:
// NReco PDF Generator
var converter = new HtmlToPdfConverter();
// IronPDF
var renderer = new ChromePdfRenderer();
// NReco PDF Generator
var converter = new HtmlToPdfConverter();
// IronPDF
var renderer = new ChromePdfRenderer();
' NReco PDF Generator
Dim converter As New HtmlToPdfConverter()
' IronPDF
Dim renderer As New ChromePdfRenderer()
问题 2:GeneratePdf 返回错误类型
问题: 代码期望PdfDocument。
解决方案: 访问.BinaryData属性:
// NReco PDF Generator
byte[] pdfBytes = converter.GeneratePdf(html);
// IronPDF
byte[] pdfBytes = renderer.RenderHtmlAsPdf(html).BinaryData;
// NReco PDF Generator
byte[] pdfBytes = converter.GeneratePdf(html);
// IronPDF
byte[] pdfBytes = renderer.RenderHtmlAsPdf(html).BinaryData;
' NReco PDF Generator
Dim pdfBytes As Byte() = converter.GeneratePdf(html)
' IronPDF
Dim pdfBytes As Byte() = renderer.RenderHtmlAsPdf(html).BinaryData
问题 3:未找到 PageMargins 对象
问题:IronPDF中不存在PageMargins类。
解决方法:使用单独的边距属性:
// NReco PDF Generator
converter.Margins = new PageMargins { Top = 10, Bottom = 10, Left = 10, Right = 10 };
// IronPDF
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
// NReco PDF Generator
converter.Margins = new PageMargins { Top = 10, Bottom = 10, Left = 10, Right = 10 };
// IronPDF
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
' NReco PDF Generator
converter.Margins = New PageMargins With {.Top = 10, .Bottom = 10, .Left = 10, .Right = 10}
' IronPDF
renderer.RenderingOptions.MarginTop = 10
renderer.RenderingOptions.MarginBottom = 10
renderer.RenderingOptions.MarginLeft = 10
renderer.RenderingOptions.MarginRight = 10
问题 4:页码未显示
问题: [topage]占位符不起作用。
解决方案:更新IronPDF占位符语法:
// NReco PDF Generator
converter.PageFooterHtml = "<div>Page [page] of [topage]</div>";
// IronPDF
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div>Page {page} of {total-pages}</div>",
MaxHeight = 20
};
// NReco PDF Generator
converter.PageFooterHtml = "<div>Page [page] of [topage]</div>";
// IronPDF
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div>Page {page} of {total-pages}</div>",
MaxHeight = 20
};
Imports NReco.PdfGenerator
Imports IronPdf
converter.PageFooterHtml = "<div>Page [page] of [topage]</div>"
renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
.HtmlFragment = "<div>Page {page} of {total-pages}</div>",
.MaxHeight = 20
}
迁移清单
迁移前
- 清点代码库中所有
NReco.PdfGenerator的使用情况 - 记录所有
CustomWkHtmlPageArgs值 列出所有带有占位符的页眉/页脚HTML模板 - 确定异步需求(Web 控制器、服务)
- 检查缩放和边距设置
- 备份现有 PDF 输出以进行比较
- 获取IronPDF许可证密钥
软件包变更
- 移除
NReco.PdfGeneratorNuGet 包 - 安装
IronPdfNuGet 包:dotnet add package IronPdf - 将命名空间导入从
using IronPdf;
代码更改
- 在启动时添加许可证密钥配置
- 用
HtmlToPdfConverter - 用
GeneratePdf(html) - 用
GeneratePdfFromFile(url, null) - 将
PageMargins对象转换为单独的边距属性 - 将缩放值从浮点数更新为百分比
- 更新占位符语法:
[page]→{page},[topage]→{total-pages} - 用
File.WriteAllBytes() - 在有利的情况下,将同步调用转换为异步调用。
后迁移
- 从项目/部署中移除 wkhtmltopdf 二进制文件
- 更新 Docker 文件以移除 wkhtmltopdf 安装
- 运行回归测试,比较 PDF 输出
- 验证页眉/页脚占位符是否正确渲染。
- 在所有目标平台(Windows、Linux、macOS)上进行测试
- 更新 CI/CD 流水线,移除 wkhtmltopdf 步骤
- 更新安全扫描以确认 CVE 已移除

