
如何在 .NET Maui 中查看 PDF 文件
從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) |
| 攻擊向量 | 網路 |
| 狀態 | 無修補版本(wkhtmltopdf執行檔已存檔) |
| 受影響 | 所有捆綁wkhtmltopdf 0.12.6的Rotativa版本 |
wkhtmltopdf GitHub儲存庫於2023年1月2日被存檔(僅讀)。維護者的狀態頁面指出該專案依賴於Qt 4(自2015年以來未受支持)和2012年的WebKit分支,並明確警告不要使用不受信任的HTML。 CVE-2022-35583沒有修補版本,因此任何使用Rotativa的應用程式都會暴露在風險中,除非HTML輸入被完全淨化。
攻擊如何運作
<!-- Attacker submits this content via your MVC model -->
<iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe>
<img src="http://internal-database:5432/admin" />
影響:
- 存取AWS/Azure/GCP雲端中繼資料端點
- 竊取內部API資料和憑據
- 內部網路端口掃描
- 窃取敏感配置
技術危機
Rotativa包裹了wkhtmltopdf,它使用了以下技術:
- Qt WebKit 4.8(自2012年)
- 無Flexbox支持
- 無CSS Grid支持
- JavaScript執行異常
- 無ES6+支持
Rotativa與IronPDF比較
| 功能 | Rotativa | IronPDF |
|---|---|---|
| 專案相容性 | 僅限ASP.NET MVC | 任何.NET專案型別(MVC、Razor Pages、Blazor等) |
| 維護 | 已被棄用 | 積極維護 |
| 安全性 | 由於wkhtmltopdf依賴性而具有漏洞(CVE-2022-35583) | 定期更新和安全修補 |
| HTML渲染 | 過時的WebKit | 現代 Chromium |
| CSS3 | 部分 | 支援 |
| Flexbox/Grid | 不支持 | 支援 |
| JavaScript | 不可靠 | 完整ES6+ |
| Razor Pages | 不支持 | 支援 |
| Blazor | 不支持 | 支援 |
| PDF 操作 | 不可用 | 全面 |
| 數位簽名 | 不可用 | 全面 |
| PDF/A合規性 | 不可用 | 全面 |
| Async/Await | 只有同步 | 全面支持異步 |
| 開源 | 是,MIT授權 | 否,商業授權 |
對於針對當前 .NET 版本的團隊,IronPDF 提供了現代化的 Chromium 渲染和跨平台支持,這是Rotativa無法提供的。
開始之前
前提條件
- .NET環境:.NET Framework 4.6.2+ 或.NET Core 3.1+ / .NET 5/6/7/8/9+
- NuGet存取: 有能力安裝NuGet套件
- IronPDF授權: 從ironpdf.com獲取您的授權金鑰
NuGet包變更
原始的Rotativa封裝目標是典型的ASP.NET MVC 5(最後發布 v1.7.3, 2017-09-29)。 社區分叉Rotativa.AspNetCore(webgio)於2024年11月6日達到v1.4.0,支持 .NET Core 3.1到 .NET 8,但這兩個封裝仍然捆綁wkhtmltopdf 0.12.6 執行檔(最後一次上游發行2020年6月)。
# Remove Rotativa
dotnet remove package Rotativa
dotnet remove package Rotativa.AspNetCore
# Install IronPDF
dotnet add package IronPdf
刪除wkhtmltopdf執行檔
從您的專案中刪除這些檔案:
wkhtmltopdf.exewkhtmltox.dll- 任何
Rotativa/資料夾
這些是CVE-2022-35583的來源。IronPDF不需要本機二進位檔執行。
授權配置
// Add in Program.cs or Startup.cs
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";' Add in Program.vb or Startup.vb
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"' Add in Program.vb or Startup.vb
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"完整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;' Before: Rotativa
Imports Rotativa
Imports Rotativa.Options
Imports Rotativa.AspNetCore
' After: IronPDF
Imports IronPdf
Imports IronPdf.Rendering' Before: Rotativa
Imports Rotativa
Imports Rotativa.Options
Imports Rotativa.AspNetCore
' After: IronPDF
Imports IronPdf
Imports IronPdf.Rendering核心類別映射
| Rotativa類別 | IronPDF等價 |
|---|---|
ViewAsPdf | ChromePdfRenderer |
ActionAsPdf | ChromePdfRenderer.RenderUrlAsPdf() |
UrlAsPdf | ChromePdfRenderer.RenderUrlAsPdf() |
Orientation枚舉 | PdfPaperOrientation枚舉 |
Size枚舉 | PdfPaperSize枚舉 |
頁面佔位符轉換
| Rotativa佔位符 | IronPDF 佔位符 |
|---|---|
[page] | {page} |
[topage] | {total-pages} |
[date] | {date} |
[time] | {time} |
[title] | {html-title} |
[sitepage] | {url} |
程式碼遷移範例
範例1:HTML轉PDF轉換
之前(Rotativa):
// NuGet: Install-Package Rotativa.AspNetCore
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.AspNetCore
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
};
}
}
}Imports Microsoft.AspNetCore.Mvc
Imports Rotativa.AspNetCore
Imports System.Threading.Tasks
Namespace RotativaExample
Public Class PdfController
Inherits Controller
Public Async Function GeneratePdf() As Task(Of IActionResult)
Dim htmlContent = "<h1>Hello World</h1><p>This is a PDF document.</p>"
'Rotavita requires returning a ViewAsPdf result from MVC controller
Return New ViewAsPdf() With {
.ViewName = "PdfView",
.PageSize = Rotativa.AspNetCore.Options.Size.A4
}
End Function
End Class
End NamespaceImports Microsoft.AspNetCore.Mvc
Imports Rotativa.AspNetCore
Imports System.Threading.Tasks
Namespace RotativaExample
Public Class PdfController
Inherits Controller
Public Async Function GeneratePdf() As Task(Of IActionResult)
Dim htmlContent = "<h1>Hello World</h1><p>This is a PDF document.</p>"
'Rotavita requires returning a ViewAsPdf result from MVC controller
Return New ViewAsPdf() With {
.ViewName = "PdfView",
.PageSize = Rotativa.AspNetCore.Options.Size.A4
}
End Function
End Class
End Namespace之後(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!");
}
}
}' NuGet: Install-Package IronPdf
Imports IronPdf
Imports System
Module IronPdfExample
Sub Main()
Dim renderer As New ChromePdfRenderer()
Dim htmlContent As String = "<h1>Hello World</h1><p>This is a PDF document.</p>"
Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs("output.pdf")
Console.WriteLine("PDF generated successfully!")
End Sub
End Module' NuGet: Install-Package IronPdf
Imports IronPdf
Imports System
Module IronPdfExample
Sub Main()
Dim renderer As New ChromePdfRenderer()
Dim htmlContent As String = "<h1>Hello World</h1><p>This is a PDF document.</p>"
Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs("output.pdf")
Console.WriteLine("PDF generated successfully!")
End Sub
End Module此範例說明基本的架構差異。 Rotativa需要從MVC控制器操作返回ViewAsPdf結果,將您與ASP.NET MVC框架綁定在一起。 這個模式僅在MVC請求管道中有效,且需要Razor視圖進行渲染。
IronPDF可以隨處運行:控制台應用程式、Web API、Blazor、Razor Pages或任何.NET專案型別。 您可以呼叫RenderHtmlAsPdf(),並使用HTML字串並儲存結果。 無需MVC控制器,不依賴於視圖。 查看更多HTML到PDF文件以獲得完整的範例。
範例2:URL轉PDF轉換
之前(Rotativa):
// NuGet: Install-Package Rotativa.AspNetCore
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.AspNetCore
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.AspNetCore
Imports Microsoft.AspNetCore.Mvc
Imports Rotativa.AspNetCore
Imports System.Threading.Tasks
Namespace RotativaExample
Public Class UrlPdfController
Inherits Controller
Public Async Function ConvertUrlToPdf() As Task(Of IActionResult)
'Rotativa works within MVC framework and returns ActionResult
Return New UrlAsPdf("https://www.example.com") With {
.FileName = "webpage.pdf",
.PageSize = Rotativa.AspNetCore.Options.Size.A4,
.PageOrientation = Rotativa.AspNetCore.Options.Orientation.Portrait
}
End Function
End Class
End Namespace' NuGet: Install-Package Rotativa.AspNetCore
Imports Microsoft.AspNetCore.Mvc
Imports Rotativa.AspNetCore
Imports System.Threading.Tasks
Namespace RotativaExample
Public Class UrlPdfController
Inherits Controller
Public Async Function ConvertUrlToPdf() As Task(Of IActionResult)
'Rotativa works within MVC framework and returns ActionResult
Return New UrlAsPdf("https://www.example.com") With {
.FileName = "webpage.pdf",
.PageSize = Rotativa.AspNetCore.Options.Size.A4,
.PageOrientation = Rotativa.AspNetCore.Options.Orientation.Portrait
}
End Function
End Class
End Namespace之後(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!");
}
}
}' NuGet: Install-Package IronPdf
Imports IronPdf
Imports System
Module IronPdfExample
Sub Main()
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("webpage.pdf")
Console.WriteLine("URL converted to PDF successfully!")
End Sub
End Module' NuGet: Install-Package IronPdf
Imports IronPdf
Imports System
Module IronPdfExample
Sub Main()
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("webpage.pdf")
Console.WriteLine("URL converted to PDF successfully!")
End Sub
End ModuleRotativa的ActionResult。 IronPDF的PdfDocument物件。 URL渲染使用現代Chromium代替wkhtmltopdf的脆弱和過時的WebKit引擎。瞭解更多內容,請參閱我們的教程。
範例3:具有頁碼的標頭和頁腳
之前(Rotativa):
// NuGet: Install-Package Rotativa.AspNetCore
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,
// Margins(top, right, bottom, left)
PageMargins = new Margins(20, 10, 20, 10),
CustomSwitches = "--header-center \"Page Header\" --footer-center \"Page [page] of [topage]\""
};
}
}
}// NuGet: Install-Package Rotativa.AspNetCore
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,
// Margins(top, right, bottom, left)
PageMargins = new Margins(20, 10, 20, 10),
CustomSwitches = "--header-center \"Page Header\" --footer-center \"Page [page] of [topage]\""
};
}
}
}Imports Microsoft.AspNetCore.Mvc
Imports Rotativa.AspNetCore
Imports Rotativa.AspNetCore.Options
Imports System.Threading.Tasks
Namespace RotativaExample
Public Class HeaderFooterController
Inherits Controller
Public Async Function GeneratePdfWithHeaderFooter() As Task(Of IActionResult)
Return New ViewAsPdf("Report") With {
.PageSize = Size.A4,
' Margins(top, right, bottom, left)
.PageMargins = New Margins(20, 10, 20, 10),
.CustomSwitches = "--header-center ""Page Header"" --footer-center ""Page [page] of [topage]"""
}
End Function
End Class
End NamespaceImports Microsoft.AspNetCore.Mvc
Imports Rotativa.AspNetCore
Imports Rotativa.AspNetCore.Options
Imports System.Threading.Tasks
Namespace RotativaExample
Public Class HeaderFooterController
Inherits Controller
Public Async Function GeneratePdfWithHeaderFooter() As Task(Of IActionResult)
Return New ViewAsPdf("Report") With {
.PageSize = Size.A4,
' Margins(top, right, bottom, left)
.PageMargins = New Margins(20, 10, 20, 10),
.CustomSwitches = "--header-center ""Page Header"" --footer-center ""Page [page] of [topage]"""
}
End Function
End Class
End Namespace之後(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!");
}
}
}' NuGet: Install-Package IronPdf
Imports IronPdf
Imports IronPdf.Rendering
Imports System
Module IronPdfExample
Sub Main(args As String())
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.TextHeader = New TextHeaderFooter() With {
.CenterText = "Page Header",
.DrawDividerLine = True
}
renderer.RenderingOptions.TextFooter = New TextHeaderFooter() With {
.CenterText = "Page {page} of {total-pages}",
.DrawDividerLine = True
}
Dim htmlContent As String = "<h1>Report Title</h1><p>Report content goes here.</p>"
Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs("report.pdf")
Console.WriteLine("PDF with headers and footers created successfully!")
End Sub
End Module' NuGet: Install-Package IronPdf
Imports IronPdf
Imports IronPdf.Rendering
Imports System
Module IronPdfExample
Sub Main(args As String())
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.TextHeader = New TextHeaderFooter() With {
.CenterText = "Page Header",
.DrawDividerLine = True
}
renderer.RenderingOptions.TextFooter = New TextHeaderFooter() With {
.CenterText = "Page {page} of {total-pages}",
.DrawDividerLine = True
}
Dim htmlContent As String = "<h1>Report Title</h1><p>Report content goes here.</p>"
Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs("report.pdf")
Console.WriteLine("PDF with headers and footers created successfully!")
End Sub
End ModuleRotativa使用[topage]的頁眉和頁尾配置。 這種基於字串的方法容易出錯且在編譯時難以驗證。
IronPDF使用強型別的DrawDividerLine的屬性。 佔位符語法從{total-pages}進行轉換。 型別化屬性提供了IntelliSense、編譯時檢查,並且沒有拼寫錯誤的風險。
僅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 integrationImports System.Web.Mvc
Public Class InvoiceController
Inherits Controller
Public Function InvoicePdf(id As Integer) As ActionResult
Dim model = GetInvoice(id)
Return New ViewAsPdf("Invoice", model) ' Tied to MVC Views
End Function
End Class
' Problems:
' - No Razor Pages support
' - No Blazor support
' - No minimal APIs support
' - No ASP.NET Core native integrationImports System.Web.Mvc
Public Class InvoiceController
Inherits Controller
Public Function InvoicePdf(id As Integer) As ActionResult
Dim model = GetInvoice(id)
Return New ViewAsPdf("Invoice", model) ' Tied to MVC Views
End Function
End Class
' Problems:
' - No Razor Pages support
' - No Blazor support
' - No minimal APIs support
' - No ASP.NET Core native integrationIronPDF將視圖渲染與PDF生成分開,這實際上更具靈活性——您可以渲染任何HTML,而不僅僅是MVC視圖。
異步模式遷移
Rotativa會阻塞執行緒; IronPDF支持完整的異步/await:
// ❌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
}' ❌Rotativa- Blocks the thread
Public Function GeneratePdf() As ActionResult
Return New ViewAsPdf("Report")
' This blocks the request thread until PDF is complete
' Poor scalability under load
End Function
' ✅IronPDF-全面支持異步support
Public Async Function GeneratePdf() As Task(Of IActionResult)
Dim renderer = New ChromePdfRenderer()
Dim pdf = Await renderer.RenderHtmlAsPdfAsync(html)
Return File(pdf.BinaryData, "application/pdf")
' Non-blocking, better scalability
End Function' ❌Rotativa- Blocks the thread
Public Function GeneratePdf() As ActionResult
Return New ViewAsPdf("Report")
' This blocks the request thread until PDF is complete
' Poor scalability under load
End Function
' ✅IronPDF-全面支持異步support
Public Async Function GeneratePdf() As Task(Of IActionResult)
Dim renderer = New ChromePdfRenderer()
Dim pdf = Await renderer.RenderHtmlAsPdfAsync(html)
Return File(pdf.BinaryData, "application/pdf")
' Non-blocking, better scalability
End Function遷移後的新能力
在遷移到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");Dim merged = PdfDocument.Merge(pdf1, pdf2, pdf3)
merged.SaveAs("complete.pdf")Dim merged = PdfDocument.Merge(pdf1, pdf2, pdf3)
merged.SaveAs("complete.pdf")數位簽名
var signature = new PdfSignature("certificate.pfx", "password");
pdf.Sign(signature);var signature = new PdfSignature("certificate.pfx", "password");
pdf.Sign(signature);Dim signature = New PdfSignature("certificate.pfx", "password")
pdf.Sign(signature)Dim signature = New PdfSignature("certificate.pfx", "password")
pdf.Sign(signature)密碼保護
pdf.SecuritySettings.UserPassword = "secret";pdf.SecuritySettings.UserPassword = "secret";pdf.SecuritySettings.UserPassword = "secret"pdf.SecuritySettings.UserPassword = "secret"水印
pdf.ApplyWatermark("<h1 style='color:red; opacity:0.3;'>DRAFT</h1>");pdf.ApplyWatermark("<h1 style='color:red; opacity:0.3;'>DRAFT</h1>");IRON VB CONVERTER ERROR developers@ironsoftware.comIRON VB CONVERTER ERROR developers@ironsoftware.comPDF/A歸檔合規性
pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b);pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b);pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b)pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b)現代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!' This now works (broke in Rotativa)
Dim html As String = "
<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>"
Dim pdf = renderer.RenderHtmlAsPdf(html) ' Works!' This now works (broke in Rotativa)
Dim html As String = "
<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>"
Dim pdf = renderer.RenderHtmlAsPdf(html) ' Works!遷移檢查表
遷移前
- 識別程式碼基中所有Rotativa的使用情況
- 文件中文字的CustomSwitches用於轉換為RenderingOptions
- 記錄頁眉/頁腳佔位符語法以進行轉換(
[page]→{page}) - 獲取IronPDF授權金鑰來自ironpdf.com
套件變更
- 刪除
Rotativa.AspNetCoreNuGet包 - 刪除wkhtmltopdf二進位檔(
wkhtmltopdf.exe,wkhtmltox.dll) - 安裝
IronPdfNuGet包
程式碼變更
- 更新命名空間導入(
using Rotativa;→using IronPdf;) - 用
ChromePdfRenderer+ViewAsPdf - 用
UrlAsPdf - 將
RenderingOptions屬性 - 更新佔位符語法(
[page]→{page},[topage]→{total-pages}) - 用個別的
PageMargins。 - 在適當位置更改為異步模式
- 在應用程式啟動時新增授權初始化
遷移後
- 驗證所有PDF生成效果正確
- 比較PDF輸出質量(Chromium渲染更準確)
- 驗證CSS渲染改進(Flexbox/Grid現在可以運行)
- 測試JavaScript執行(現在使用Chromium更可靠)
- 確認安全掃描通過(不再有CVE-2022-35583標誌)
- 更新Docker配置以刪除wkhtmltopdf安裝
Curtis Chau擁有Carleton大學的電腦科學學士學位,專精於前端開發,擁有Node.js、TypeScript、JavaScript和React的專業知識。Curtis熱衷於建立直觀且美觀的使用者介面,喜愛使用現代框架並建立結構良好、視覺吸引力的手冊。
相關文章


