迁移指南 如何用 C# 从 Rotativa 迁移到 IronPDF Curtis Chau 已发布:2026年2月1日 下载 IronPDF NuGet 下载 DLL 下载 Windows 安装程序 免费试用 法学硕士副本 法学硕士副本 将页面复制为 Markdown 格式,用于 LLMs 在 ChatGPT 中打开 向 ChatGPT 咨询此页面 在双子座打开 向 Gemini 询问此页面 在 Grok 中打开 向 Grok 询问此页面 打开困惑 向 Perplexity 询问有关此页面的信息 分享 在 Facebook 上分享 分享到 X(Twitter) 在 LinkedIn 上分享 复制链接 电子邮件文章 从Rotativa迁移到IronPDF可解决关键的安全漏洞,同时实现 PDF 生成工作流程的现代化。 本指南提供了一个完整的、循序渐进的迁移路径,消除了废弃的 wkhtmltopdf 依赖性,实现了对现代 CSS 和 JavaScript 的支持,并提供了超越 ASP.NET MVC 的跨平台兼容性。 为何从Rotativa迁移到 IronPDF. 了解 Rotativa. Rotativa 长期以来一直是开发人员在 C# 中生成 PDF 的热门选择。 它利用 wkhtmltopdf 工具将 HTML 内容转换为 PDF 格式。Rotativa是专为 ASP.NET MVC 应用程序设计的开源库。 然而,虽然Rotativa吸引了大量受众,但它对过时技术栈的依赖也带来了挑战,这些挑战可能不是每个开发人员都能立即意识到的。 Rotativa 的核心是提供一种简单的方法,将 PDF 生成集成到 ASP.NET MVC 项目中,并利用 wkhtmltopdf 实现其后台功能。 重要安全咨询 Rotativa封装了wkhtmltopdf,该文件存在严重的未编译安全漏洞。 属性 价值 CVE ID CVE-2022-35583 严重性 关键 (9.8/10) 攻击向量 网络 状态 永不打补丁 受影响 所有Rotativa版本 wkhtmltopdf已于2022年12月正式废弃。维护者明确表示他们不会修复安全漏洞。 每个使用Rotativa的应用程序都会永久暴露。 攻击如何工作 <iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe> <img src="http://internal-database:5432/admin" /> <iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe> <img src="http://internal-database:5432/admin" /> HTML 影响: 访问 AWS/Azure/GCP 云元数据端点 窃取内部 API 数据和凭证 端口扫描内部网络 渗出敏感配置 技术危机 Rotativa 对 wkhtmltopdf 进行了包装,后者使用的是.NET: Qt WebKit 4.8(2012 年起) 不支持 Flexbox 不支持 CSS 网格 JavaScript 执行中断 不支持 ES6+ Rotativa与IronPDF对比 特征 Rotativa IronPDF 项目兼容性 仅限 ASP.NET MVC 任何 .NET 项目类型(MVC、Razor Pages、Blazor 等) 维护 放弃 积极维护 安全性 由于 wkhtmltopdf 依赖关系而存在漏洞 (CVE-2022-35583) 定期更新和安全补丁 HTML 渲染 过时的 WebKit 现代 Chromium CSS3代码 部分翻译 全面支持 Flexbox/网格 不支持 全面支持 JavaScript语言 不可靠 完整的 ES6+ Razor页面 不支持 全面支持 Blazor 不支持 全面支持 PDF 操作 不可用 满的 数字签名 不可用 满的 PDF/A合规性 不可用 满的 同步/等待 仅同步 完全异步 开放源代码 是,MIT 许可 否,商业许可 对于计划在 2025 年和 2026 年之前采用 .NET 10 和 C# 14 的团队,IronPDF 可提供Rotativa无法提供的现代 Chromium 渲染和跨平台支持。 开始之前 前提条件 .NET 环境: .NET Framework 4.6.2+ 或 .NET Core 3.1+ / .NET 5/6/7/8/9+ NuGet 访问权限:能够安装 NuGet 包 IronPDF 许可证:请从ironpdf.com获取您的许可证密钥。 NuGet 软件包变更 # Remove Rotativa dotnet remove package Rotativa dotnet remove package Rotativa.AspNetCore # Install IronPDF dotnet add package IronPdf # Remove Rotativa dotnet remove package Rotativa dotnet remove package Rotativa.AspNetCore # Install IronPDF dotnet add package IronPdf SHELL 删除 wkhtmltopdf 二进制文件 从您的项目中删除这些文件: wkhtmltopdf.exe wkhtmltox.dll 任何 Rotativa/ 文件夹 这些就是CVE-2022-35583的源头。IronPdf 不需要本地二进制文件。 许可配置 // Add in Program.cs or Startup.cs IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"; // Add in Program.cs or Startup.cs IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"; $vbLabelText $csharpLabel 完整的 API 参考 命名空间变更 // Before: Rotativa using Rotativa; using Rotativa.Options; using Rotativa.AspNetCore; // After: IronPDF using IronPdf; using IronPdf.Rendering; // Before: Rotativa using Rotativa; using Rotativa.Options; using Rotativa.AspNetCore; // After: IronPDF using IronPdf; using IronPdf.Rendering; $vbLabelText $csharpLabel 核心类映射 Rotativa 类 IronPdf 同等产品 备注 ViewAsPdf ChromePdfRenderer 渲染 HTML ActionAsPdf ChromePdfRenderer.RenderUrlAsPdf() 渲染 URL UrlAsPdf ChromePdfRenderer.RenderUrlAsPdf() 渲染 URL 方向</code>枚举|PdfPaperOrientation` 枚举 定位 大小</code>枚举|PdfPaperSize` 枚举 纸张大小 页面占位符转换 Rotativa 占位符 IronPdf 占位符 [页面]|{page}` [topage] {总页数} [日期] {日期} [时间] {时间} [标题] {html-title} [网站页面] {url} 代码迁移示例 示例 1:HTML 到 PDF 的转换 之前 (Rotativa): // NuGet: Install-Package Rotativa.Core using Microsoft.AspNetCore.Mvc; using Rotativa.AspNetCore; using System.Threading.Tasks; namespace RotativaExample { public class PdfController : Controller { public async Task<IActionResult> GeneratePdf() { var htmlContent = "<h1>Hello World</h1><p>This is a PDF document.</p>"; //Rotativarequires returning a ViewAsPdf result from MVC controller return new ViewAsPdf() { ViewName = "PdfView", PageSize = Rotativa.AspNetCore.Options.Size.A4 }; } } } // NuGet: Install-Package Rotativa.Core using Microsoft.AspNetCore.Mvc; using Rotativa.AspNetCore; using System.Threading.Tasks; namespace RotativaExample { public class PdfController : Controller { public async Task<IActionResult> GeneratePdf() { var htmlContent = "<h1>Hello World</h1><p>This is a PDF document.</p>"; //Rotativarequires returning a ViewAsPdf result from MVC controller return new ViewAsPdf() { ViewName = "PdfView", PageSize = Rotativa.AspNetCore.Options.Size.A4 }; } } } $vbLabelText $csharpLabel After (IronPDF): // NuGet: Install-Package IronPdf using IronPdf; using System; namespace IronPdfExample { class Program { static void Main(string[] args) { var renderer = new ChromePdfRenderer(); var htmlContent = "<h1>Hello World</h1><p>This is a PDF document.</p>"; var pdf = renderer.RenderHtmlAsPdf(htmlContent); pdf.SaveAs("output.pdf"); Console.WriteLine("PDF generated successfully!"); } } } // NuGet: Install-Package IronPdf using IronPdf; using System; namespace IronPdfExample { class Program { static void Main(string[] args) { var renderer = new ChromePdfRenderer(); var htmlContent = "<h1>Hello World</h1><p>This is a PDF document.</p>"; var pdf = renderer.RenderHtmlAsPdf(htmlContent); pdf.SaveAs("output.pdf"); Console.WriteLine("PDF generated successfully!"); } } } $vbLabelText $csharpLabel 本例展示了基本的架构差异。Rotativa要求从 MVC 控制器动作返回ViewAsPdf`结果,从而将您与 ASP.NET MVC Framework 绑定。 该模式仅适用于 MVC 请求管道,并需要 Razor 视图来呈现。 IronPDF 适用于任何地方:控制台应用程序、Web API、Blazor、Razor Pages 或任何 .NET 项目类型。 您使用 HTML 字符串调用 RenderHtmlAsPdf() 并保存结果。 无需 MVC 控制器,不依赖视图。 请参阅 HTML 转 PDF 文档,了解全面的示例。 示例 2:URL 到 PDF 的转换 之前 (Rotativa): // NuGet: Install-Package Rotativa.Core using Microsoft.AspNetCore.Mvc; using Rotativa.AspNetCore; using System.Threading.Tasks; namespace RotativaExample { public class UrlPdfController : Controller { public async Task<IActionResult> ConvertUrlToPdf() { //Rotativaworks within MVC framework and returns ActionResult return new UrlAsPdf("https://www.example.com") { FileName = "webpage.pdf", PageSize = Rotativa.AspNetCore.Options.Size.A4, PageOrientation = Rotativa.AspNetCore.Options.Orientation.Portrait }; } } } // NuGet: Install-Package Rotativa.Core using Microsoft.AspNetCore.Mvc; using Rotativa.AspNetCore; using System.Threading.Tasks; namespace RotativaExample { public class UrlPdfController : Controller { public async Task<IActionResult> ConvertUrlToPdf() { //Rotativaworks within MVC framework and returns ActionResult return new UrlAsPdf("https://www.example.com") { FileName = "webpage.pdf", PageSize = Rotativa.AspNetCore.Options.Size.A4, PageOrientation = Rotativa.AspNetCore.Options.Orientation.Portrait }; } } } $vbLabelText $csharpLabel After (IronPDF): // NuGet: Install-Package IronPdf using IronPdf; using System; namespace IronPdfExample { class Program { static void Main(string[] args) { var renderer = new ChromePdfRenderer(); var pdf = renderer.RenderUrlAsPdf("https://www.example.com"); pdf.SaveAs("webpage.pdf"); Console.WriteLine("URL converted to PDF successfully!"); } } } // NuGet: Install-Package IronPdf using IronPdf; using System; namespace IronPdfExample { class Program { static void Main(string[] args) { var renderer = new ChromePdfRenderer(); var pdf = renderer.RenderUrlAsPdf("https://www.example.com"); pdf.SaveAs("webpage.pdf"); Console.WriteLine("URL converted to PDF successfully!"); } } } $vbLabelText $csharpLabel Rotativa 的UrlAsPdf类需要从 MVC 控制器返回 ActionResult 结果。IronPDF的 RenderUrlAsPdf() 方法可在任何上下文中调用,并直接返回 PdfDocument 对象。 URL 渲染使用的是现代 Chromium 引擎,而不是 wkhtmltopdf 脆弱过时的 WebKit 引擎。请在我们的教程中了解更多信息。 示例 3:带页码的页眉和页脚 之前 (Rotativa): // NuGet: Install-Package Rotativa.Core using Microsoft.AspNetCore.Mvc; using Rotativa.AspNetCore; using Rotativa.AspNetCore.Options; using System.Threading.Tasks; namespace RotativaExample { public class HeaderFooterController : Controller { public async Task<IActionResult> GeneratePdfWithHeaderFooter() { return new ViewAsPdf("Report") { PageSize = Size.A4, PageMargins = new Margins(20, 10, 20, 10), CustomSwitches = "--header-center \"Page Header\" --footer-center \"Page [page] of [toPage]\"" }; } } } // NuGet: Install-Package Rotativa.Core using Microsoft.AspNetCore.Mvc; using Rotativa.AspNetCore; using Rotativa.AspNetCore.Options; using System.Threading.Tasks; namespace RotativaExample { public class HeaderFooterController : Controller { public async Task<IActionResult> GeneratePdfWithHeaderFooter() { return new ViewAsPdf("Report") { PageSize = Size.A4, PageMargins = new Margins(20, 10, 20, 10), CustomSwitches = "--header-center \"Page Header\" --footer-center \"Page [page] of [toPage]\"" }; } } } $vbLabelText $csharpLabel After (IronPDF): // NuGet: Install-Package IronPdf using IronPdf; using IronPdf.Rendering; using System; namespace IronPdfExample { class Program { static void Main(string[] args) { var renderer = new ChromePdfRenderer(); renderer.RenderingOptions.TextHeader = new TextHeaderFooter() { CenterText = "Page Header", DrawDividerLine = true }; renderer.RenderingOptions.TextFooter = new TextHeaderFooter() { CenterText = "Page {page} of {total-pages}", DrawDividerLine = true }; var htmlContent = "<h1>Report Title</h1><p>Report content goes here.</p>"; var pdf = renderer.RenderHtmlAsPdf(htmlContent); pdf.SaveAs("report.pdf"); Console.WriteLine("PDF with headers and footers created successfully!"); } } } // NuGet: Install-Package IronPdf using IronPdf; using IronPdf.Rendering; using System; namespace IronPdfExample { class Program { static void Main(string[] args) { var renderer = new ChromePdfRenderer(); renderer.RenderingOptions.TextHeader = new TextHeaderFooter() { CenterText = "Page Header", DrawDividerLine = true }; renderer.RenderingOptions.TextFooter = new TextHeaderFooter() { CenterText = "Page {page} of {total-pages}", DrawDividerLine = true }; var htmlContent = "<h1>Report Title</h1><p>Report content goes here.</p>"; var pdf = renderer.RenderHtmlAsPdf(htmlContent); pdf.SaveAs("report.pdf"); Console.WriteLine("PDF with headers and footers created successfully!"); } } } $vbLabelText $csharpLabel Rotativa 使用 CustomSwitches 将命令行参数传递给 wkhtmltopdf,包括带有占位符(如[页面]和 [toPage] )的页眉和页脚配置。 这种基于字符串的方法容易出错,而且很难在编译时进行验证。 IronPDF 使用强类型的 TextHeaderFooter 对象,该对象具有 CenterText 和 DrawDividerLine 等属性。 占位符语法从[页面]变为{page},从 [toPage] 变为{总页数}。 类型化属性提供了智能提示、编译时检查功能,而且不会出现错别字。 仅 MVC 架构问题 Rotativa 专为 ASP.NET MVC 5 及更早版本设计: // ❌Rotativa- Only works with classic MVC pattern public class InvoiceController : Controller { public ActionResult InvoicePdf(int id) { var model = GetInvoice(id); return new ViewAsPdf("Invoice", model); // Tied to MVC Views } } // Problems: // - No Razor Pages support // - No Blazor support // - No minimal APIs support // - No ASP.NET Core native integration // ❌Rotativa- Only works with classic MVC pattern public class InvoiceController : Controller { public ActionResult InvoicePdf(int id) { var model = GetInvoice(id); return new ViewAsPdf("Invoice", model); // Tied to MVC Views } } // Problems: // - No Razor Pages support // - No Blazor support // - No minimal APIs support // - No ASP.NET Core native integration $vbLabelText $csharpLabel IronPDF 将视图渲染与 PDF 生成分离开来,这实际上更加灵活--您可以渲染任何 HTML,而不仅仅是 MVC 视图。 同步模式迁移 Rotativa 阻断了线程; IronPdf 支持完全异步/等待: // ❌Rotativa- Blocks the thread public ActionResult GeneratePdf() { return new ViewAsPdf("Report"); // This blocks the request thread until PDF is complete // Poor scalability under load } // ✅IronPDF-完全异步support public async Task<IActionResult> GeneratePdf() { var renderer = new ChromePdfRenderer(); var pdf = await renderer.RenderHtmlAsPdfAsync(html); return File(pdf.BinaryData, "application/pdf"); // Non-blocking, better scalability } // ❌Rotativa- Blocks the thread public ActionResult GeneratePdf() { return new ViewAsPdf("Report"); // This blocks the request thread until PDF is complete // Poor scalability under load } // ✅IronPDF-完全异步support public async Task<IActionResult> GeneratePdf() { var renderer = new ChromePdfRenderer(); var pdf = await renderer.RenderHtmlAsPdfAsync(html); return File(pdf.BinaryData, "application/pdf"); // Non-blocking, better scalability } $vbLabelText $csharpLabel 迁移后的新功能 迁移到IronPDF后,您将获得Rotativa无法提供的功能: PDF 合并 var merged = PdfDocument.Merge(pdf1, pdf2, pdf3); merged.SaveAs("complete.pdf"); var merged = PdfDocument.Merge(pdf1, pdf2, pdf3); merged.SaveAs("complete.pdf"); $vbLabelText $csharpLabel 数字签名 var signature = new PdfSignature("certificate.pfx", "password"); pdf.Sign(signature); var signature = new PdfSignature("certificate.pfx", "password"); pdf.Sign(signature); $vbLabelText $csharpLabel 密码保护 pdf.SecuritySettings.UserPassword = "secret"; pdf.SecuritySettings.UserPassword = "secret"; $vbLabelText $csharpLabel 水印 pdf.ApplyWatermark("<h1 style='color:red; opacity:0.3;'>DRAFT</h1>"); pdf.ApplyWatermark("<h1 style='color:red; opacity:0.3;'>DRAFT</h1>"); $vbLabelText $csharpLabel PDF/A 存档合规性 pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b); pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b); $vbLabelText $csharpLabel 现代 CSS 支持 // This now works (broke in Rotativa) var html = @" <div style='display: flex; justify-content: space-between;'> <div>Left</div> <div>Right</div> </div> <div style='display: grid; grid-template-columns: 1fr 1fr 1fr;'> <div>Col 1</div><div>Col 2</div><div>Col 3</div> </div>"; var pdf = renderer.RenderHtmlAsPdf(html); // Works! // This now works (broke in Rotativa) var html = @" <div style='display: flex; justify-content: space-between;'> <div>Left</div> <div>Right</div> </div> <div style='display: grid; grid-template-columns: 1fr 1fr 1fr;'> <div>Col 1</div><div>Col 2</div><div>Col 3</div> </div>"; var pdf = renderer.RenderHtmlAsPdf(html); // Works! $vbLabelText $csharpLabel 迁移清单 迁移前 识别代码库中所有Rotativa的使用情况 文档 CustomSwitches 用于转换为 RenderingOptions 注意页眉/页脚占位符的转换语法([页面]→{page}) 从ironpdf.com获取IronPDF许可证密钥 软件包变更 删除Rotativa和Rotativa.AspNetCore NuGet 包 删除 wkhtmltopdf 二进制文件( wkhtmltopdf.exe 、 wkhtmltox.dll ) 安装IronPdf NuGet 包 代码更改 更新命名空间导入( using Rotativa; → using IronPdf; ) 将ViewAsPdf替换为ChromePdfRenderer + RenderHtmlAsPdf() 将UrlAsPdf替换为RenderUrlAsPdf() 将CustomSwitches转换为RenderingOptions属性 更新占位符语法([页面]→{page},[topage]→{总页数}) 将PageMargins替换为单独的MarginTop / MarginBottom / MarginLeft / MarginRight 在适当情况下改为异步模式 在应用程序启动时添加许可证初始化 后迁移 验证所有 PDF 生成功能是否正常 比较 PDF 输出质量(Chromium 的渲染更准确) 验证 CSS 渲染改进(Flexbox/Grid 现在可以正常工作) 测试 JavaScript 执行(现在使用 Chromium 内核已稳定运行) 验证安全扫描通过(不再有CVE-2022-35583标志) 更新 Docker 配置以移除 wkhtmltopdf 安装 Curtis Chau 立即与工程团队聊天 技术作家 Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。 相关文章 已发布2026年2月1日 如何用 C# 从 ZetPDF 迁移到 IronPDF 通过这本完整的 C# 指南,掌握从 ZetPDF 到 IronPDF 的迁移。从基于坐标的库转换到现代的 HTML 到 PDF 解决方案。包括 HTML 转换、合并 PDF 和移除 PDFSharp 依赖性的代码示例。 阅读更多 已发布2026年2月1日 如何用 C# 从 Scryber.Core 迁移到 IronPDF 通过这本完整的 C# 指南,掌握从 Scryber.Core 迁移到 IronPDF 的方法。从自定义 XML/HTML 解析转换到现代 Chromium 渲染器。包括 HTML 转换、URL 呈现和替换专有绑定的代码示例。 阅读更多 已发布2026年2月1日 如何用 C# 从 XFINIUM.PDF 迁移到 IronPDF 通过这本完整的 C# 指南,掌握从 XFINIUM.PDF 到 IronPDF 的迁移。从基于坐标的手动定位切换到声明式 HTML/CSS 渲染。包括替换图形基元和自动布局的代码示例。 阅读更多 如何用 C# 从 SAP Crystal Reports 迁移到 IronPDF如何用 C# 从 RawPrint 迁移到...
已发布2026年2月1日 如何用 C# 从 ZetPDF 迁移到 IronPDF 通过这本完整的 C# 指南,掌握从 ZetPDF 到 IronPDF 的迁移。从基于坐标的库转换到现代的 HTML 到 PDF 解决方案。包括 HTML 转换、合并 PDF 和移除 PDFSharp 依赖性的代码示例。 阅读更多
已发布2026年2月1日 如何用 C# 从 Scryber.Core 迁移到 IronPDF 通过这本完整的 C# 指南,掌握从 Scryber.Core 迁移到 IronPDF 的方法。从自定义 XML/HTML 解析转换到现代 Chromium 渲染器。包括 HTML 转换、URL 呈现和替换专有绑定的代码示例。 阅读更多
已发布2026年2月1日 如何用 C# 从 XFINIUM.PDF 迁移到 IronPDF 通过这本完整的 C# 指南,掌握从 XFINIUM.PDF 到 IronPDF 的迁移。从基于坐标的手动定位切换到声明式 HTML/CSS 渲染。包括替换图形基元和自动布局的代码示例。 阅读更多