如何用 C# 从 Nutrient.io 迁移到 IronPDF
从 Nutrient.io(原 PSPDFKit)迁移到IronPDFfor .NET,从具有异步优先模式的复杂文档智能平台迁移到具有直接同步 API 的专注 PDF 库,从而简化了您的 .NET PDF 工作流程。本指南提供了一个全面、逐步的迁移路径,可消除平台开销,同时保持所有基本的 PDF 功能。
为什么要从 Nutrient.io 迁移到 IronPDF.
平台复杂性问题
Nutrient.io(前身为 PSPDFKit)已从 PDF SDK 发展成为一个全面的 "文档智能平台"。这种转变在拓宽功能的同时,也给只需要可靠 PDF 操作的团队带来了巨大的挑战:
1.平台过度设计:曾经的 PDF SDK 现在已经发展成为一个完整的文档智能平台,具有 AI 功能和文档工作流功能,但对于简单的 PDF 任务来说,这些功能可能并不必要。
2.企业定价: Nutrient.io 的目标客户是大型组织,其定价不透明,需要联系销售部门。 这给中小型团队造成了障碍,也使预算规划变得困难。
3.品牌重塑带来的混乱: PSPDFKit → Nutrient 的过渡导致文档中同时出现两个名称,造成文档混乱。软件包名称可能仍然使用 PSPDFKit,过渡期间的迁移路径也尚不明确。
4.异步优先的复杂性: Nutrient.io 中的所有操作都需要 async/await 模式。 即使是简单的操作也需要PdfProcessor.CreateAsync()进行初始化,基本任务需要使用异步方法,从而增加了同步工作流的开销。
5.依赖项较多:完整平台需要更多资源,软件包占用空间更大,初始化时间更长,并且需要额外的配置。
Nutrient.io 与IronPDF对比
| 方面 | Nutrient.io (PSPDFKit) | IronPDF |
|---|---|---|
| 翻译重点 | 文档智能平台 | PDF 库 |
| 定价 | 企业(联系销售) | 透明、公开 |
| 结构 | 复杂的平台 | 简单库 |
| API 风格 | 异步优先 | 同步与异步选项 |
| 依赖关系 | 重型 | 轻量级 |
| 配置 | 复杂的配置对象 | 简单明了的属性 |
| 学习曲线 | 陡峭(平台) | 温和(库) |
| 目标用户 | 企业 | 所有团队规模 |
对于计划在 2025 年和 2026 年之前采用 .NET 10 和 C# 14 的团队来说,IronPDF 提供了一个更简单的基础,可以干净利落地集成,而不需要完整文档智能平台的开销。
开始之前
前提条件
- .NET 环境: .NET Framework 4.6.2+ 或 .NET Core 3.1+ / .NET 5/6/7/8/9+
- NuGet 访问权限:能够安装 NuGet 包
- IronPDF 许可证:请从ironpdf.com获取您的许可证密钥。
NuGet 软件包变更
# Remove Nutrient/PSPDFKit packages
dotnet remove package PSPDFKit.NET
dotnet remove package PSPDFKit.PDF
dotnet remove package Nutrient
dotnet remove package Nutrient.PDF
# Install IronPDF
dotnet add package IronPdf# Remove Nutrient/PSPDFKit packages
dotnet remove package PSPDFKit.NET
dotnet remove package PSPDFKit.PDF
dotnet remove package Nutrient
dotnet remove package Nutrient.PDF
# Install IronPDF
dotnet add package IronPdf许可配置
// 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";识别 Nutrient.io 的用法
# Find all Nutrient/PSPDFKit references
grep -r "PSPDFKit\|Nutrient\|PdfProcessor\|PdfConfiguration" --include="*.cs" .# Find all Nutrient/PSPDFKit references
grep -r "PSPDFKit\|Nutrient\|PdfProcessor\|PdfConfiguration" --include="*.cs" .完整的 API 参考
初始化映射
| Nutrient.io (PSPDFKit) | IronPDF | 备注 |
|---|---|---|
| <代码>等待 PdfProcessor.CreateAsync()</ 代码 | <代码>new ChromePdfRenderer()</ 代码 | 无需异步 |
| <代码>processor.Dispose()</代码 | (自动或手动) | 更简单的生命周期 |
new PdfConfiguration { ... } | <代码>renderer.RenderingOptions</代码 | 基于属性 |
文档加载映射
| Nutrient.io (PSPDFKit) | IronPDF | 备注 |
|---|---|---|
| <代码>等待处理器.OpenAsync(路径)</代码 | <代码>PdfDocument.FromFile(路径)</代码 | 默认同步 |
| <代码>Document.LoadFromStream(stream)</代码 | <代码>PdfDocument.FromStream(流)</代码 | 流支持 |
| <代码>Document.LoadFromBytes(字节)</代码 | <代码>new PdfDocument(字节)</代码 | 字节数组 |
PDF 生成映射
| Nutrient.io (PSPDFKit) | IronPDF | 备注 |
|---|---|---|
| <代码>等待处理器.GeneratePdfFromHtmlStringAsync(html)</代码 | <代码>renderer.RenderHtmlAsPdf(html)</代码 | 同步方法 |
await processor.GeneratePdfFromUrlAsync(url)<br | <代码>renderer.RenderUrlAsPdf(url)</代码 | 直接 URL |
| <代码>await processor.GeneratePdfFromFileAsync(path)</ 代码 | <代码>renderer.RenderHtmlFileAsPdf(path)</代码 | HTML 文件 |
文档操作映射
| Nutrient.io (PSPDFKit) | IronPDF | 备注 |
|---|---|---|
| <代码>等待处理器.MergeAsync(docs)</代码 | <代码>PdfDocument.Merge(pdfs)</代码 | 同步 |
| <代码>document.PageCount</代码 | <代码>pdf.PageCount</代码 | 相同模式 |
| <代码>等待 document.SaveAsync(path)</ 代码 | <代码>pdf.SaveAs(路径)</代码 | 同步 |
| <代码>document.ToBytes()</代码 | <代码>pdf.BinaryData</代码 | 字节数组 |
注释和水印映射
| Nutrient.io (PSPDFKit) | IronPDF | 备注 |
|---|---|---|
| <代码>等待 document.AddAnnotationAsync(index, annotation)</ 代码 | <代码>pdf.ApplyWatermark(html)</代码 | 基于 HTML |
| <代码>new TextAnnotation("text")</ 代码 | 水印中的 HTML | 更灵活 |
| <代码>annotation.Opacity = 0.5</代码 | CSS <代码>不透明度:0.5</代码 | CSS 定型 |
| <代码>annotation.FontSize = 48</ 代码 | CSS font-size: 48px | CSS 定型 |
代码迁移示例
示例 1:HTML 到 PDF 的转换
之前(Nutrient.io):
// NuGet: Install-Package PSPDFKit.Dotnet
using PSPDFKit.Pdf;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var htmlContent = "<html><body><h1>Hello World</h1></body></html>";
using var processor = await PdfProcessor.CreateAsync();
var document = await processor.GeneratePdfFromHtmlStringAsync(htmlContent);
await document.SaveAsync("output.pdf");
}
}// NuGet: Install-Package PSPDFKit.Dotnet
using PSPDFKit.Pdf;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var htmlContent = "<html><body><h1>Hello World</h1></body></html>";
using var processor = await PdfProcessor.CreateAsync();
var document = await processor.GeneratePdfFromHtmlStringAsync(htmlContent);
await document.SaveAsync("output.pdf");
}
}After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var htmlContent = "<html><body><h1>Hello World</h1></body></html>";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("output.pdf");
}
}// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var htmlContent = "<html><body><h1>Hello World</h1></body></html>";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("output.pdf");
}
}Nutrient.io 方法需要几个异步步骤:使用<代码>等待 PdfProcessor.CreateAsync()</ 代码创建 PdfProcessor ,然后调用 await processor.GeneratePdfFromHtmlStringAsync() ,最后调用 await document.SaveAsync() 。 整个方法必须标记为async Task,处理器需要使用using语句进行正确处理。
IronPdf 大幅简化了这一工作。 创建ChromePdfRenderer,调用RenderHtmlAsPdf(),并使用SaveAs()保存。 不需要 async/await,不需要管理处理器生命周期,也不需要 using 块来进行简单操作。 对于在 PDF 工作流程中不需要异步模式的开发人员来说,这种模式更为直观。 有关其他渲染选项,请参阅 HTML to PDF 文档。
示例 2:合并多个 PDF 文件
之前(Nutrient.io):
// NuGet: Install-Package PSPDFKit.Dotnet
using PSPDFKit.Pdf;
using System.Threading.Tasks;
using System.Collections.Generic;
class Program
{
static async Task Main()
{
using var processor = await PdfProcessor.CreateAsync();
var document1 = await processor.OpenAsync("document1.pdf");
var document2 = await processor.OpenAsync("document2.pdf");
var mergedDocument = await processor.MergeAsync(new List<PdfDocument> { document1, document2 });
await mergedDocument.SaveAsync("merged.pdf");
}
}// NuGet: Install-Package PSPDFKit.Dotnet
using PSPDFKit.Pdf;
using System.Threading.Tasks;
using System.Collections.Generic;
class Program
{
static async Task Main()
{
using var processor = await PdfProcessor.CreateAsync();
var document1 = await processor.OpenAsync("document1.pdf");
var document2 = await processor.OpenAsync("document2.pdf");
var mergedDocument = await processor.MergeAsync(new List<PdfDocument> { document1, document2 });
await mergedDocument.SaveAsync("merged.pdf");
}
}After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using System.Collections.Generic;
class Program
{
static void Main()
{
var pdf1 = PdfDocument.FromFile("document1.pdf");
var pdf2 = PdfDocument.FromFile("document2.pdf");
var merged = PdfDocument.Merge(pdf1, pdf2);
merged.SaveAs("merged.pdf");
}
}// NuGet: Install-Package IronPdf
using IronPdf;
using System.Collections.Generic;
class Program
{
static void Main()
{
var pdf1 = PdfDocument.FromFile("document1.pdf");
var pdf2 = PdfDocument.FromFile("document2.pdf");
var merged = PdfDocument.Merge(pdf1, pdf2);
merged.SaveAs("merged.pdf");
}
}Nutrient.io 的合并操作需要使用<代码>等待 PdfProcessor.CreateAsync()</ 代码创建一个处理器,使用单独的 await processor.OpenAsync() 调用打开每个文档,创建一个 List<PdfDocument> ,使用该列表调用 await processor.MergeAsync() ,最后调用 await mergedDocument.SaveAsync() 。 这就是基本合并的五个异步操作。
IronPDF 将此简化为四行同步操作:使用 PdfDocument.FromFile() 加载每个 PDF,使用静态 PdfDocument.Merge() 方法合并,然后保存。 无处理器生命周期,无需创建列表(可直接传递文档),无异步开销。 了解有关 合并和拆分 PDF 的更多信息。
示例 3:添加水印
之前(Nutrient.io):
// NuGet: Install-Package PSPDFKit.Dotnet
using PSPDFKit.Pdf;
using PSPDFKit.Pdf.Annotation;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
using var processor = await PdfProcessor.CreateAsync();
var document = await processor.OpenAsync("document.pdf");
for (int i = 0; i < document.PageCount; i++)
{
var watermark = new TextAnnotation("CONFIDENTIAL")
{
Opacity = 0.5,
FontSize = 48
};
await document.AddAnnotationAsync(i, watermark);
}
await document.SaveAsync("watermarked.pdf");
}
}// NuGet: Install-Package PSPDFKit.Dotnet
using PSPDFKit.Pdf;
using PSPDFKit.Pdf.Annotation;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
using var processor = await PdfProcessor.CreateAsync();
var document = await processor.OpenAsync("document.pdf");
for (int i = 0; i < document.PageCount; i++)
{
var watermark = new TextAnnotation("CONFIDENTIAL")
{
Opacity = 0.5,
FontSize = 48
};
await document.AddAnnotationAsync(i, watermark);
}
await document.SaveAsync("watermarked.pdf");
}
}After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Editing;
class Program
{
static void Main()
{
var pdf = PdfDocument.FromFile("document.pdf");
pdf.ApplyWatermark("<h1 style='color:gray;opacity:0.5;'>CONFIDENTIAL</h1>",
50,
VerticalAlignment.Middle,
HorizontalAlignment.Center);
pdf.SaveAs("watermarked.pdf");
}
}// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Editing;
class Program
{
static void Main()
{
var pdf = PdfDocument.FromFile("document.pdf");
pdf.ApplyWatermark("<h1 style='color:gray;opacity:0.5;'>CONFIDENTIAL</h1>",
50,
VerticalAlignment.Middle,
HorizontalAlignment.Center);
pdf.SaveAs("watermarked.pdf");
}
}这个例子突出了一个基本的架构差异。 Nutrient.io 使用基于注释的方法:您创建一个TextAnnotation对象,其中包含Opacity和FontSize等属性,然后遍历每个页面,对每个页面调用await document.AddAnnotationAsync(i, watermark) 。 这就需要了解注释系统并自己管理循环。
IronPDF 使用基于 HTML 的方法: ApplyWatermark()方法接受带有 CSS 样式的 HTML 字符串。 水印会在一次调用中自动应用到所有页面。 您可以通过熟悉的 CSS 属性(color、opacity、font-size)而不是特定于注解的对象属性来控制外观。 这种方法提供了更大的样式灵活性--您可以使用任何 HTML/CSS,包括渐变、图像和复杂布局。 请参阅水印文档以获取更高级的示例。
关键迁移说明
同步到同步转换
最大的改动是删除了不必要的 async/await 模式:
// Nutrient.io: Async-first
using var processor = await PdfProcessor.CreateAsync();
var document = await processor.GeneratePdfFromHtmlStringAsync(html);
await document.SaveAsync("output.pdf");
// IronPDF:默认同步(async available when needed)
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");// Nutrient.io: Async-first
using var processor = await PdfProcessor.CreateAsync();
var document = await processor.GeneratePdfFromHtmlStringAsync(html);
await document.SaveAsync("output.pdf");
// IronPDF:默认同步(async available when needed)
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");如果您确实需要异步操作,IronPDF 提供了异步变体,如 RenderHtmlAsPdfAsync() 。
消除处理器生命周期
Nutrient.io 需要创建和处理处理器:
// Nutrient.io: Processor lifecycle management
using var processor = await PdfProcessor.CreateAsync();
// ... use processor ...
// Processor disposed at end of using block
// IronPDF: No processor lifecycle
var renderer = new ChromePdfRenderer();
// Reuse renderer, no complex lifecycle management// Nutrient.io: Processor lifecycle management
using var processor = await PdfProcessor.CreateAsync();
// ... use processor ...
// Processor disposed at end of using block
// IronPDF: No processor lifecycle
var renderer = new ChromePdfRenderer();
// Reuse renderer, no complex lifecycle management配置模式更改
Nutrient.io 使用配置对象; IronPdf 使用属性:
// Nutrient.io: Config object
var config = new PdfConfiguration
{
PageSize = PageSize.A4,
Margins = new Margins(20, 20, 20, 20)
};
var doc = await processor.GeneratePdfFromHtmlStringAsync(html, config);
// IronPDF: Properties on RenderingOptions
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.MarginLeft = 20;
renderer.RenderingOptions.MarginRight = 20;
var pdf = renderer.RenderHtmlAsPdf(html);// Nutrient.io: Config object
var config = new PdfConfiguration
{
PageSize = PageSize.A4,
Margins = new Margins(20, 20, 20, 20)
};
var doc = await processor.GeneratePdfFromHtmlStringAsync(html, config);
// IronPDF: Properties on RenderingOptions
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.MarginLeft = 20;
renderer.RenderingOptions.MarginRight = 20;
var pdf = renderer.RenderHtmlAsPdf(html);注释到 HTML 水印
用 HTML 字符串替换注释对象:
// Nutrient.io: Annotation object with properties
new TextAnnotation("CONFIDENTIAL") { Opacity = 0.5f, FontSize = 48 }
// IronPDF: HTML with CSS
"<h1 style='opacity:0.5; font-size:48px;'>CONFIDENTIAL</h1>"// Nutrient.io: Annotation object with properties
new TextAnnotation("CONFIDENTIAL") { Opacity = 0.5f, FontSize = 48 }
// IronPDF: HTML with CSS
"<h1 style='opacity:0.5; font-size:48px;'>CONFIDENTIAL</h1>"页码处理
Nutrient.io 需要手动计算页数; IronPdf 已内置占位符:
// Nutrient.io: Manual loop and page counting
for (int i = 0; i < doc.PageCount; i++)
{
var footer = new TextAnnotation($"Page {i + 1} of {doc.PageCount}");
await doc.AddAnnotationAsync(i, footer);
}
// IronPDF: Built-in placeholders
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "Page {page} of {total-pages}"
};// Nutrient.io: Manual loop and page counting
for (int i = 0; i < doc.PageCount; i++)
{
var footer = new TextAnnotation($"Page {i + 1} of {doc.PageCount}");
await doc.AddAnnotationAsync(i, footer);
}
// IronPDF: Built-in placeholders
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "Page {page} of {total-pages}"
};故障排除
问题 1:未找到 PdfProcessor
问题:IronPDF中不存在PdfProcessor类。
解决方案:使用ChromePdfRenderer :
// Nutrient.io
using var processor = await PdfProcessor.CreateAsync();
// IronPDF
var renderer = new ChromePdfRenderer();// Nutrient.io
using var processor = await PdfProcessor.CreateAsync();
// IronPDF
var renderer = new ChromePdfRenderer();问题 2:GeneratePdfFromHtmlStringAsync 未找到
问题:不存在异步 HTML 方法。
解决方案:使用RenderHtmlAsPdf() :
// Nutrient.io
var document = await processor.GeneratePdfFromHtmlStringAsync(html);
// IronPDF
var pdf = renderer.RenderHtmlAsPdf(html);// Nutrient.io
var document = await processor.GeneratePdfFromHtmlStringAsync(html);
// IronPDF
var pdf = renderer.RenderHtmlAsPdf(html);问题 3:未找到文本注释
问题:IronPDF中不存在注释类。
解决方案:使用基于 HTML 的水印:
// Nutrient.io
var watermark = new TextAnnotation("DRAFT") { Opacity = 0.5 };
await document.AddAnnotationAsync(0, watermark);
// IronPDF
pdf.ApplyWatermark("<div style='opacity:0.5;'>DRAFT</div>");// Nutrient.io
var watermark = new TextAnnotation("DRAFT") { Opacity = 0.5 };
await document.AddAnnotationAsync(0, watermark);
// IronPDF
pdf.ApplyWatermark("<div style='opacity:0.5;'>DRAFT</div>");问题 4:未找到 MergeAsync
问题:不存在异步合并方法。
解决方案:使用静态的PdfDocument.Merge()方法:
// Nutrient.io
var mergedDocument = await processor.MergeAsync(documentList);
// IronPDF
var merged = PdfDocument.Merge(pdf1, pdf2);// Nutrient.io
var mergedDocument = await processor.MergeAsync(documentList);
// IronPDF
var merged = PdfDocument.Merge(pdf1, pdf2);迁移清单
迁移前
- 清点代码库中所有 PSPDFKit/营养素的使用情况
- 记录可能需要调整的异步模式 列出所有配置对象及其属性
- 识别基于标注的特征(水印、标题)
- 审查表单处理要求
- 获取IronPDF许可证密钥
软件包变更
- 删除
PSPDFKit.NETNuGet 包 - 删除
NutrientNuGet 包 安装IronPdfNuGet 包:dotnet add package IronPdf - 更新命名空间导入
代码更改
- 在启动时添加许可证密钥配置
- 将
PdfProcessor.CreateAsync()替换为new ChromePdfRenderer() - 将
processor.GeneratePdfFromHtmlStringAsync()替换为renderer.RenderHtmlAsPdf() - 将
processor.MergeAsync()替换为PdfDocument.Merge() - 将
TextAnnotation水印转换为 HTML 水印 - 将配置对象替换为
RenderingOptions属性 - 更新页眉/页脚,使用带有占位符的
HtmlHeaderFooter组件 - 删除不必要的 async/await 模式
后迁移
- 移除不再需要的 async/await
- 运行回归测试,比较 PDF 输出
- 核对页眉/页脚的页码
- 测试水印渲染
- 更新 CI/CD 流水线






