如何在 .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輸入被完全淨化。
攻擊如何運作
<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" />
影響:
- 存取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
# 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.cs or Startup.cs
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
核心類別映射
| 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 As String = "<h1>Hello World</h1><p>This is a PDF document.</p>"
' Rotativa 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!");
}
}
}
Imports IronPdf
Imports System
Namespace IronPdfExample
Class Program
Shared Sub Main(ByVal args As String())
Dim renderer = New ChromePdfRenderer()
Dim htmlContent = "<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 Class
End Namespace
此範例說明基本的架構差異。 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
};
}
}
}
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!");
}
}
}
Imports IronPdf
Imports System
Namespace IronPdfExample
Class Program
Shared Sub Main(ByVal args As String())
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("webpage.pdf")
Console.WriteLine("URL converted to PDF successfully!")
End Sub
End Class
End Namespace
Rotativa的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 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!");
}
}
}
Imports IronPdf
Imports IronPdf.Rendering
Imports System
Namespace IronPdfExample
Class Program
Shared Sub Main(ByVal args As String())
Dim renderer = 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 = "<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 Class
End Namespace
Rotativa使用[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 integration
Imports 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 integration
IronPDF將視圖渲染與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 As 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")
數位簽名
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)
密碼保護
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.com
PDF/A歸檔合規性
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!
遷移檢查表
遷移前
- 識別程式碼基中所有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安裝

