跳至页脚内容
迁移指南

如何用 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 提供了一个更简单的基础,可以干净利落地集成,而不需要完整文档智能平台的开销。


开始之前

前提条件

  1. .NET 环境: .NET Framework 4.6.2+ 或 .NET Core 3.1+ / .NET 5/6/7/8/9+
  2. NuGet 访问权限:能够安装 NuGet 包
  3. 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
SHELL

许可配置

// 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";
$vbLabelText   $csharpLabel

识别 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" .
SHELL

完整的 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");
    }
}
$vbLabelText   $csharpLabel

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");
    }
}
$vbLabelText   $csharpLabel

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");
    }
}
$vbLabelText   $csharpLabel

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");
    }
}
$vbLabelText   $csharpLabel

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");
    }
}
$vbLabelText   $csharpLabel

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");
    }
}
$vbLabelText   $csharpLabel

这个例子突出了一个基本的架构差异。 Nutrient.io 使用基于注释的方法:您创建一个TextAnnotation对象,其中包含OpacityFontSize等属性,然后遍历每个页面,对每个页面调用await document.AddAnnotationAsync(i, watermark) 。 这就需要了解注释系统并自己管理循环。

IronPDF 使用基于 HTML 的方法: ApplyWatermark()方法接受带有 CSS 样式的 HTML 字符串。 水印会在一次调用中自动应用到所有页面。 您可以通过熟悉的 CSS 属性(coloropacityfont-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");
$vbLabelText   $csharpLabel

如果您确实需要异步操作,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
$vbLabelText   $csharpLabel

配置模式更改

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);
$vbLabelText   $csharpLabel

注释到 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>"
$vbLabelText   $csharpLabel

页码处理

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}"
};
$vbLabelText   $csharpLabel

故障排除

问题 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();
$vbLabelText   $csharpLabel

问题 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);
$vbLabelText   $csharpLabel

问题 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>");
$vbLabelText   $csharpLabel

问题 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);
$vbLabelText   $csharpLabel

迁移清单

迁移前

  • 清点代码库中所有 PSPDFKit/营养素的使用情况
  • 记录可能需要调整的异步模式 列出所有配置对象及其属性
  • 识别基于标注的特征(水印、标题)
  • 审查表单处理要求
  • 获取IronPDF许可证密钥

软件包变更

  • 删除PSPDFKit.NET NuGet 包
  • 删除Nutrient NuGet 包 安装IronPdf NuGet 包: 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 流水线

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。