如何在 C# 中從 SelectPdf 轉移到 IronPDF
從選擇 PDF轉移到IronPDF可將您的 PDF 生成工作流程從過時渲染引擎的 Windows 專用解決方案轉換為完全支援 CSS3 和 JavaScript 的現代化跨平台函式庫。 本指南提供了完整的、按步驟進行的遷移路徑,可以部署到 Linux、Docker、Azure Functions 以及選擇 PDF無法支援的其他雲端平台。
為何要從選擇 PDF轉移到 IronPDF?
瞭解 SelectPdf
SelectPdf 是一個商用函式庫,設計用來使用 C# 將 HTML 內容轉換成 PDF。 該資料庫專為需要在其應用程式中無縫整合 PDF 生成功能的開發人員量身打造。選擇 PDF的優勢在於其簡單的 API,使其成為 PDF 生成新手的吸引人的選擇。
然而,潛在使用者必須了解其重要的限制。 儘管SelectPdf宣稱具有跨平台的功能,但它只能在Windows環境下運作。 在考慮以雲端為基礎的部署解決方案(例如Azure 功能或 Docker 等容器)時,這會造成很大的障礙。 此外,其免費版有很大的限制,在套用強烈的水印前最多只能翻譯五頁。選擇 PDF利用過時的 Blink fork 和基於 WebKit 的架構,這會造成與CSS 網格和進階 flexbox 等現代網頁技術的相容性問題。
選擇 PDF的關鍵限制
| 問題 | 影響力 | IronPDF 解決方案 |
|---|---|---|
| 僅限視窗使用。 | 無法部署至 Linux、Docker、Azure Functions | 完全跨平台支援 |
| 過時的呈現引擎 | 現代 CSS 失敗,佈局破壞 | 最新的 Chromium |
| 5頁免費版本限制 | 5 頁之後的強烈水印 | 慷慨的試用 |
| 不支援 .NET 10 | 面向未來的問題 | 完全支援 .NET 10 |
| 雲端部署受阻 | 無法使用 AWS Lambda、Azure Functions | 雲端原生 |
選擇 PDF與IronPDF的比較
| 特點 | 選擇 PDF | IronPDF |
|---|---|---|
| 平台支援 | 僅限 Windows | 完全跨平台,10 個以上的發行版 |
| 支援現代網路標準 | 有限 (過時 Blink) | 完整 CSS3、現代 Chromium |
| 最大免費版本頁數限制 | 5 頁 | 靈活、無硬性限制 |
| 定價 | 起價 499 美元 | 透明且靈活的定價 |
| .NET 10 支援。 | 無 | 支援 |
| 雲端環境中的部署 | 不支援 | 完全支援 |
| CSS 網格 | 限額 | 支援 |
| <強>Flexbox</強 | 限額 | 支援 |
| CSS 變數 | 不支援 | 支援 |
| Docker | 不支援 | 官方圖片 |
| Azure 功能 | 不支援 | 支援 |
| AWS Lambda。 | 不支援 | 支援 |
對於計劃在 2025 年和 2026 年之前採用 .NET 10 和 C# 14 的團隊而言,SelectPdf 明確表示不支援 .NET 10,造成面向未來的問題。IronPDF提供對所有現代 .NET 版本的完整支援。
開始之前
先決條件
- .NET 環境: .NET Framework 4.6.2+ 或 .NET Core 3.1+ / .NET 5/6/7/8/9/10+
- NuGet存取權限:能夠安裝NuGet套件
- IronPDF許可證:請從IronPDF取得您的許可證密鑰。
NuGet 套件變更
# Remove SelectPdf
dotnet remove package Select.HtmlToPdf
# Install IronPDF
dotnet add package IronPdf
# Remove SelectPdf
dotnet remove package Select.HtmlToPdf
# Install IronPDF
dotnet add package IronPdf
授權組態
// Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
' Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
完整的 API 參考資料
命名空間變更
// Before: SelectPdf
using SelectPdf;
// After: IronPDF
using IronPdf;
using IronPdf.Engines.Chrome;
// Before: SelectPdf
using SelectPdf;
// After: IronPDF
using IronPdf;
using IronPdf.Engines.Chrome;
' Before: SelectPdf
Imports SelectPdf
' After: IronPDF
Imports IronPdf
Imports IronPdf.Engines.Chrome
核心 API 對應
| 選擇 PDF | IronPDF | 筆記 |
|---|---|---|
HtmlToPdf |
ChromePdfRenderer |
核心轉換器類別 |
converter.ConvertHtmlString(html) |
renderer.RenderHtmlAsPdf(html) |
HTML 字串轉換 |
converter.ConvertUrl(url) |
renderer.RenderUrlAsPdf(url) |
URL 轉換 |
doc.Save(path) |
pdf.SaveAs(path) |
儲存至檔案 |
doc.Close() |
不需要 | IronPDF 處理清理工作 |
converter.Options.PdfPageSize |
renderer.RenderingOptions.PaperSize |
紙張大小 |
converter.Options.PdfPageOrientation |
renderer.RenderingOptions.PaperOrientation |
導向 |
converter.Options.MarginTop |
renderer.RenderingOptions.MarginTop |
頂端邊緣 |
converter.Options.MarginBottom |
renderer.RenderingOptions.MarginBottom |
底邊 |
converter.Options.MarginLeft |
renderer.RenderingOptions.MarginLeft |
左邊距離 |
converter.Options.MarginRight |
renderer.RenderingOptions.MarginRight |
右邊距 |
PdfPageSize.A4 |
PdfPaperSize.A4 |
A4 大小的枚舉 |
PdfPageOrientation.Portrait |
PdfPaperOrientation.Portrait |
肖像枚舉 |
PdfPageOrientation.Landscape |
PdfPaperOrientation.Landscape |
景觀枚舉 |
{page_number} |
{page} |
頁碼占位符 |
{total_pages} |
{total-pages} |
總頁數 |
程式碼遷移範例
範例 1:HTML 字串至 PDF 的轉換
之前 (SelectPdf):
// NuGet: Install-Package Select.HtmlToPdf
using SelectPdf;
using System;
class Program
{
static void Main()
{
string htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
HtmlToPdf converter = new HtmlToPdf();
PdfDocument doc = converter.ConvertHtmlString(htmlContent);
doc.Save("document.pdf");
doc.Close();
Console.WriteLine("PDF generated from HTML string");
}
}
// NuGet: Install-Package Select.HtmlToPdf
using SelectPdf;
using System;
class Program
{
static void Main()
{
string htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
HtmlToPdf converter = new HtmlToPdf();
PdfDocument doc = converter.ConvertHtmlString(htmlContent);
doc.Save("document.pdf");
doc.Close();
Console.WriteLine("PDF generated from HTML string");
}
}
Imports SelectPdf
Imports System
Class Program
Shared Sub Main()
Dim htmlContent As String = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>"
Dim converter As New HtmlToPdf()
Dim doc As PdfDocument = converter.ConvertHtmlString(htmlContent)
doc.Save("document.pdf")
doc.Close()
Console.WriteLine("PDF generated from HTML string")
End Sub
End Class
After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
string htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("document.pdf");
Console.WriteLine("PDF generated from HTML string");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
string htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("document.pdf");
Console.WriteLine("PDF generated from HTML string");
}
}
Imports IronPdf
Imports System
Class Program
Shared Sub Main()
Dim htmlContent As String = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>"
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs("document.pdf")
Console.WriteLine("PDF generated from HTML string")
End Sub
End Class
本範例展示了核心 API 的差異。選擇 PDF使用 HtmlToPdf 作為轉換器類,呼叫 ConvertHtmlString() 建立 PdfDocument,然後呼叫 Save() 和 Close() 進行持久化和清理。
IronPDF 使用 ChromePdfRenderer 和 RenderHtmlAsPdf(),返回 PdfDocument,該 SaveAs() 儲存。 取消了 Close() 呼叫—IronPDF 會自動處理資源管理。 請參閱 HTML to PDF 文件,以瞭解全面的範例。
範例 2:URL 到 PDF 的轉換
之前 (SelectPdf):
// NuGet: Install-Package Select.HtmlToPdf
using SelectPdf;
using System;
class Program
{
static void Main()
{
HtmlToPdf converter = new HtmlToPdf();
PdfDocument doc = converter.ConvertUrl("https://www.example.com");
doc.Save("output.pdf");
doc.Close();
Console.WriteLine("PDF created successfully");
}
}
// NuGet: Install-Package Select.HtmlToPdf
using SelectPdf;
using System;
class Program
{
static void Main()
{
HtmlToPdf converter = new HtmlToPdf();
PdfDocument doc = converter.ConvertUrl("https://www.example.com");
doc.Save("output.pdf");
doc.Close();
Console.WriteLine("PDF created successfully");
}
}
Imports SelectPdf
Imports System
Class Program
Shared Sub Main()
Dim converter As New HtmlToPdf()
Dim doc As PdfDocument = converter.ConvertUrl("https://www.example.com")
doc.Save("output.pdf")
doc.Close()
Console.WriteLine("PDF created successfully")
End Sub
End Class
After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF created successfully");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF created successfully");
}
}
Imports IronPdf
Imports System
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("output.pdf")
Console.WriteLine("PDF created successfully")
End Sub
End Class
SelectPdf 的 ConvertUrl() 方法直接對應到IronPDF的 RenderUrlAsPdf()。 關鍵的差異在於渲染引擎:SelectPdf 使用過時的 Blink/WebKit fork,在現代 CSS 方面有困難,而IronPDF則使用最新穩定的 Chromium,可完整支援 CSS3 與 JavaScript。 請參閱我們的 教學,瞭解更多資訊。
範例 3:自訂頁面設定與邊界
之前 (SelectPdf):
// NuGet: Install-Package Select.HtmlToPdf
using SelectPdf;
using System;
class Program
{
static void Main()
{
HtmlToPdf converter = new HtmlToPdf();
converter.Options.PdfPageSize = PdfPageSize.A4;
converter.Options.PdfPageOrientation = PdfPageOrientation.Portrait;
converter.Options.MarginTop = 20;
converter.Options.MarginBottom = 20;
converter.Options.MarginLeft = 20;
converter.Options.MarginRight = 20;
string html = "<html><body><h1>Custom Page Settings</h1></body></html>";
PdfDocument doc = converter.ConvertHtmlString(html);
doc.Save("custom-settings.pdf");
doc.Close();
Console.WriteLine("PDF with custom settings created");
}
}
// NuGet: Install-Package Select.HtmlToPdf
using SelectPdf;
using System;
class Program
{
static void Main()
{
HtmlToPdf converter = new HtmlToPdf();
converter.Options.PdfPageSize = PdfPageSize.A4;
converter.Options.PdfPageOrientation = PdfPageOrientation.Portrait;
converter.Options.MarginTop = 20;
converter.Options.MarginBottom = 20;
converter.Options.MarginLeft = 20;
converter.Options.MarginRight = 20;
string html = "<html><body><h1>Custom Page Settings</h1></body></html>";
PdfDocument doc = converter.ConvertHtmlString(html);
doc.Save("custom-settings.pdf");
doc.Close();
Console.WriteLine("PDF with custom settings created");
}
}
Imports SelectPdf
Imports System
Module Program
Sub Main()
Dim converter As New HtmlToPdf()
converter.Options.PdfPageSize = PdfPageSize.A4
converter.Options.PdfPageOrientation = PdfPageOrientation.Portrait
converter.Options.MarginTop = 20
converter.Options.MarginBottom = 20
converter.Options.MarginLeft = 20
converter.Options.MarginRight = 20
Dim html As String = "<html><body><h1>Custom Page Settings</h1></body></html>"
Dim doc As PdfDocument = converter.ConvertHtmlString(html)
doc.Save("custom-settings.pdf")
doc.Close()
Console.WriteLine("PDF with custom settings created")
End Sub
End Module
After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Engines.Chrome;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Portrait;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.MarginLeft = 20;
renderer.RenderingOptions.MarginRight = 20;
string html = "<html><body><h1>Custom Page Settings</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("custom-settings.pdf");
Console.WriteLine("PDF with custom settings created");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Engines.Chrome;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Portrait;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.MarginLeft = 20;
renderer.RenderingOptions.MarginRight = 20;
string html = "<html><body><h1>Custom Page Settings</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("custom-settings.pdf");
Console.WriteLine("PDF with custom settings created");
}
}
Imports IronPdf
Imports IronPdf.Engines.Chrome
Imports System
Module Program
Sub Main()
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Portrait
renderer.RenderingOptions.MarginTop = 20
renderer.RenderingOptions.MarginBottom = 20
renderer.RenderingOptions.MarginLeft = 20
renderer.RenderingOptions.MarginRight = 20
Dim html As String = "<html><body><h1>Custom Page Settings</h1></body></html>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("custom-settings.pdf")
Console.WriteLine("PDF with custom settings created")
End Sub
End Module
頁面設定模式幾乎完全相同,只是直接更改屬性名稱:
converter.Options.PdfPageSize→renderer.RenderingOptions.PaperSizeconverter.Options.PdfPageOrientation→renderer.RenderingOptions.PaperOrientationPdfPageSize.A4→PdfPaperSize.A4PdfPageOrientation.Portrait→PdfPaperOrientation.Portrait
邊界屬性保持相同的名稱和單位。
僅限 Windows 的問題
選擇 PDF的平台限制
儘管有各種行銷宣傳,但SelectPdf明確表示不支持:
- Linux (任何發行版)
- MacOS
- Docker 容器
- Azure 功能
- AWS Lambda
- Google 雲端功能
- 任何基於 ARM 的系統
這是基本的架構限制-SelectPdf 依賴 Windows 特定的函式庫,無法移植。
平台支援比較
|平台|選擇 PDF|IronPDF| | ---------- | :---: | :---: ||Windows Server 2019+| ✅ | ✅ ||視窗 10/11| ✅ | ✅ ||Ubuntu 20.04+| ❌ | ✅ ||Debian 10+| ❌ | ✅ ||CentOS 7+| ❌ | ✅ ||高山 Linux| ❌ | ✅ ||亞馬遜 Linux 2| ❌ | ✅ ||macOS 10.15+| ❌ | ✅ ||Azure 應用程式服務 (Linux)| ❌ | ✅ ||Azure 功能| ❌ | ✅ ||AWS Lambda| ❌ | ✅ ||Docker (Linux)| ❌ | ✅ ||Kubernetes| ❌ | ✅ |
過時的渲染引擎
CSS 功能支援比較
SelectPdf 使用過時的 Blink/WebKit fork,跟不上現代網路標準的腳步:
| CSS 功能 | 選擇 PDF | IronPDF |
|---|---|---|
| CSS 網格 | ⚠️ 部分/已破譯 | ✅ 全文 |
| Flexbox (基本) | ✅ | ✅ |
| Flexbox (間隙屬性) | ❌ | ✅ |
| CSS 變數 | ❌ | ✅ |
| CSS calc() | ⚠️ 有限公司 | ✅ |
| @ 媒體印刷 | ⚠️ 有限公司 | ✅ |
| @font-face | ⚠️ 有限公司 | ✅ |
| 網頁字型 | ⚠️ 有限公司 | ✅ |
| SVG | ⚠️ 基本 | ✅ 全文 |
| CSS 變形 | ⚠️ 有限公司 | ✅ |
| CSS 動畫 | ❌ | ✅ |
遷移後的新功能
轉移到IronPDF之後,您將獲得選擇 PDF無法提供的功能:
跨平台部署
// ✅IronPDF- Works everywhere
using IronPdf;
//Azure 應用程式服務 (Linux)- WORKS
// Docker container - WORKS
//AWS Lambda- WORKS
// GitHub Actions on ubuntu-latest - WORKS
// macOS development - WORKS
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello</h1>");
pdf.SaveAs("output.pdf");
// ✅IronPDF- Works everywhere
using IronPdf;
//Azure 應用程式服務 (Linux)- WORKS
// Docker container - WORKS
//AWS Lambda- WORKS
// GitHub Actions on ubuntu-latest - WORKS
// macOS development - WORKS
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello</h1>");
pdf.SaveAs("output.pdf");
Imports IronPdf
'Azure 應用程式服務 (Linux)- WORKS
' Docker container - WORKS
'AWS Lambda- WORKS
' GitHub Actions on ubuntu-latest - WORKS
' macOS development - WORKS
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Hello</h1>")
pdf.SaveAs("output.pdf")
現代 CSS 支援
// ✅IronPDF- Uses latest stable Chromium
var renderer = new ChromePdfRenderer();
var html = @"
<style>
:root { --primary: #007bff; --gap: 20px; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--gap); }
</style>
<div class='grid'>
<div style='background: var(--primary); color: white; padding: 1rem;'>Item 1</div>
<div style='background: var(--primary); color: white; padding: 1rem;'>Item 2</div>
<div style='background: var(--primary); color: white; padding: 1rem;'>Item 3</div>
</div>";
var pdf = renderer.RenderHtmlAsPdf(html);
// All modern CSS features render correctly!
// ✅IronPDF- Uses latest stable Chromium
var renderer = new ChromePdfRenderer();
var html = @"
<style>
:root { --primary: #007bff; --gap: 20px; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--gap); }
</style>
<div class='grid'>
<div style='background: var(--primary); color: white; padding: 1rem;'>Item 1</div>
<div style='background: var(--primary); color: white; padding: 1rem;'>Item 2</div>
<div style='background: var(--primary); color: white; padding: 1rem;'>Item 3</div>
</div>";
var pdf = renderer.RenderHtmlAsPdf(html);
// All modern CSS features render correctly!
Imports IronPdf
' ✅IronPDF- Uses latest stable Chromium
Dim renderer As New ChromePdfRenderer()
Dim html As String = "
<style>
:root { --primary: #007bff; --gap: 20px; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--gap); }
</style>
<div class='grid'>
<div style='background: var(--primary); color: white; padding: 1rem;'>Item 1</div>
<div style='background: var(--primary); color: white; padding: 1rem;'>Item 2</div>
<div style='background: var(--primary); color: white; padding: 1rem;'>Item 3</div>
</div>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
' All modern CSS features render correctly!
不需要 Close()
IronPDF 自動處理資源管理:
// Option 1: Let garbage collection handle it
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
// No Close() needed
// Option 2: Explicit disposal
using (var pdf = renderer.RenderHtmlAsPdf(html))
{
pdf.SaveAs("output.pdf");
}
// Option 1: Let garbage collection handle it
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
// No Close() needed
// Option 2: Explicit disposal
using (var pdf = renderer.RenderHtmlAsPdf(html))
{
pdf.SaveAs("output.pdf");
}
' Option 1: Let garbage collection handle it
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
' No Close() needed
' Option 2: Explicit disposal
Using pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
End Using
遷移清單
預遷移
- 審核程式碼庫中所有選擇 PDF的使用情況
- 記錄目前轉換器選項的映射
- 確定頁首/頁尾的實作方式
- 檢查頁碼佔位符語法(
{page_number}→{page}) - 注意基本 URL 處理模式
- 驗證目標部署平台
- 從ironpdf.com取得IronPDF許可證金鑰
程式碼更新
- 刪除
Select.HtmlToPdfNuGet 套件 - 安裝
IronPdfNuGet 套件 - 更新命名空間導入(
using SelectPdf;→using IronPdf;) - 將
HtmlToPdf替換為ChromePdfRenderer - 將
ConvertHtmlString()替換為RenderHtmlAsPdf() - 將
ConvertUrl()替換為RenderUrlAsPdf() - 更新選項屬性名稱(
Options.PdfPageSize→RenderingOptions.PaperSize) - 將
PdfPageSize轉換為PdfPaperSize - 將
PdfPageOrientation轉換為PdfPaperOrientation - 將
doc.Save()替換為pdf.SaveAs() - 刪除所有
doc.Close()調用 - 修正頁碼佔位符(
{page_number}→{page},{total_pages}→{total-pages}) - 在應用程式啟動時新增許可證初始化
後遷移
- 執行所有單元測試
- 驗證 CSS 渲染效果(尤其是 Grid/Flexbox 佈局)
- 測試 JavaScript 執行
- 核對頁首/頁尾頁碼
- 在目標平台(Linux、Docker 等)上進行測試
- 效能測試
- 比較 PDF 輸出品質
- 更新 CI/CD 管線
- 測試雲端部署(如適用)

