如何在 C# 中將 Gotenberg 遷移到 IronPDF
從 哥登堡 遷移到 IronPDF 會將您的 .NET PDF 工作流程從基於 Docker 的微服務架構和 HTTP API 呼叫轉換為進程內原生 C# 程式庫。 本指南為專業 .NET 開發人員提供了一條全面的、循序漸進的遷移路徑,消除了基礎設施開銷、網路延遲和容器管理複雜性。
為什麼要從 哥登堡 遷移到 IronPDF
哥登堡建築問題
Gotenberg 是一個基於 Docker 的微服務架構,用於產生 PDF 檔案。 雖然功能強大且靈活,但它為 C# 應用程式帶來了顯著的複雜性:
1.基礎架構開銷:需要 Docker、容器編排(Kubernetes/Docker Compose)、服務發現和負載平衡。 每次部署都會變得更加複雜。
2.網路延遲:每次 PDF 操作都需要向單獨的服務發起 HTTP 請求,每次請求會增加 10-100 毫秒以上的延遲。在高流量場景下,這種延遲會迅速累積。
3.冷啟動問題:容器啟動可能會為首次請求增加 2-5 秒的時間。 每次 Pod 重新啟動、每次擴充、每次部署都會觸發冷啟動。
4.操作複雜性:您必須將容器健康狀況、擴充功能、日誌記錄和監控作為與主應用程式分開的獨立問題進行管理。
5.多部分錶單資料:每個請求都需要建立 multipart/form-data 有效負載-冗長、容易出錯且難以維護。
6.故障點:網路逾時、服務不可用和容器崩潰等問題都需要您負責處理。
7.版本管理: 哥登堡 圖片的更新與您的應用程式是分開的; API變更可能會導致整合意外中斷。
哥登堡 與 IronPDF 的比較
| 方面 | 哥登堡 | IronPDF |
|---|---|---|
| 部署 | Docker容器+編排 | 單一 NuGet 套件 |
| 建築學 | 微服務(REST API) | 行程內庫 |
| 每次請求的延遲 | 10-100毫秒以上(網路往返時間) | 開銷小於 1 毫秒 |
| 冷啟動 | 2-5秒(容器初始化) | 1-2秒(僅限首次渲染) |
| 基礎設施 | Docker、Kubernetes、負載平衡器 | 無需 |
| 故障模式 | 網路、容器、服務故障 | 標準 .NET 異常 |
| API 風格 | REST multipart/form-data | 原生 C# 方法調用 |
| 規模化 | 水平方向(更多容器) | 垂直(進行中) |
| 偵錯 | 需要分散式追蹤 | 標準偵錯工具 |
| 版本控制 | 容器圖像標籤 | NuGet 套件版本 |
對於計劃在 2025 年和 2026 年採用 .NET 10 和 C# 14 的團隊,IronPDF 提供了一個面向未來的基礎架構,它沒有任何基礎設施依賴性,並且可以與現代 .NET 模式原生整合。
遷移複雜度評估
各功能預計工作量
| 特徵 | 遷移複雜性 | 筆記 |
|---|---|---|
| HTML 轉 PDF | 非常低 | 直接替代法 |
| PDF檔案的URL | 非常低 | 直接替代法 |
| 自訂紙張尺寸 | 低的 | 基於屬性的配置 |
| 邊際 | 低的 | 單位換算(英吋→毫米) |
| PDF合併 | 低的 | 靜態方法調用 |
| 頁首/頁尾 | 中等的 | 不同的佔位符語法 |
| 等待延遲 | 低的 | 將字串轉換為毫秒 |
| PDF/A 轉換 | 低的 | 方法呼叫而非參數 |
範式轉移
Gotenberg 遷移的根本轉變在於從使用 multipart 表單資料的 HTTP API 呼叫轉變為原生 C# 方法呼叫:
哥登堡:透過 HTTP POST multipart/form-data 向 Docker 容器發送請求
IronPDF:直接呼叫 C# 物件的方法開始之前
先決條件
- .NET 版本: IronPDF 支援 .NET Framework 4.6.2+ 和 .NET Core 3.1+ / .NET 5/6/7/8/9+ 2.許可證密鑰:從ironpdf.com取得您的 IronPDF 許可證密鑰。 3.規劃基礎設施移除:記錄哥登堡容器在遷移後的退役事宜
識別所有哥德堡用法
# Find direct HTTP calls to Gotenberg
grep -r "gotenberg\|/forms/chromium\|/forms/libreoffice\|/forms/pdfengines" --include="*.cs" .
# Find GotenbergSharpApiClient usage
grep -r "GotenbergSharpClient\|Gotenberg.Sharp\|ChromiumRequest" --include="*.cs" .
# Find Docker/Kubernetes 哥登堡 configuration
grep -r "gotenberg/gotenberg\|gotenberg:" --include="*.yml" --include="*.yaml" .# Find direct HTTP calls to Gotenberg
grep -r "gotenberg\|/forms/chromium\|/forms/libreoffice\|/forms/pdfengines" --include="*.cs" .
# Find GotenbergSharpApiClient usage
grep -r "GotenbergSharpClient\|Gotenberg.Sharp\|ChromiumRequest" --include="*.cs" .
# Find Docker/Kubernetes 哥登堡 configuration
grep -r "gotenberg/gotenberg\|gotenberg:" --include="*.yml" --include="*.yaml" .NuGet 套件變更
# Remove 哥登堡 client (if using)
dotnet remove package Gotenberg.Sharp.API.Client
# Install IronPDF
dotnet add package IronPdf# Remove 哥登堡 client (if using)
dotnet remove package Gotenberg.Sharp.API.Client
# Install IronPDF
dotnet add package IronPdf快速入門遷移
步驟 1:更新許可證配置
之前(哥德堡):
Gotenberg 不需要許可證,但需要帶有容器 URL 的 Docker 基礎架構。
private readonly string _gotenbergUrl = "http://localhost:3000";private readonly string _gotenbergUrl = "http://localhost:3000";(IronPDF 之後):
// Set once at application startup
IronPdf.License.LicenseKey = "YOUR-IRONPDF-LICENSE-KEY";// Set once at application startup
IronPdf.License.LicenseKey = "YOUR-IRONPDF-LICENSE-KEY";步驟 2:更新命名空間導入
// Before (Gotenberg)
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
// After (IronPDF)
using IronPdf;
using IronPdf.Rendering;// Before (Gotenberg)
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
// After (IronPDF)
using IronPdf;
using IronPdf.Rendering;完整 API 參考
哥登堡端點到 IronPDF 映射
| 哥德堡路線 | IronPDF當量 | 筆記 |
|---|---|---|
POST /forms/chromium/convert/html | ChromePdfRenderer.RenderHtmlAsPdf() | 將 HTML 字串轉換為 PDF |
POST /forms/chromium/convert/url | ChromePdfRenderer.RenderUrlAsPdf() | PDF檔案的URL |
POST /forms/pdfengines/merge | PdfDocument.Merge() | 合併多個PDF文件 |
POST /forms/pdfengines/convert | 使用設定呼叫pdf.SaveAs() | PDF/A 轉換 |
GET /health | 不適用 | 無需外部服務 |
表單參數到渲染選項的映射
| 哥登堡參數 | IronPDF屬性 | 轉換票據 |
|---|---|---|
paperWidth (英吋) | RenderingOptions.PaperSize | 使用枚舉或自訂大小 |
paperHeight (英吋) | RenderingOptions.PaperSize | 使用枚舉或自訂大小 |
marginTop (吋) | RenderingOptions.MarginTop | 乘以 25.4 得到毫米 |
marginBottom (英吋) | RenderingOptions.MarginBottom | 乘以 25.4 得到毫米 |
printBackground | RenderingOptions.PrintHtmlBackgrounds | 布林值 |
landscape | RenderingOptions.PaperOrientation | Landscape枚舉 |
waitDelay | RenderingOptions.RenderDelay | 轉換為毫秒 |
程式碼遷移範例
範例 1:基本 HTML 轉 PDF
之前(哥德堡):
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergExample
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
var html = "<html><body><h1>Hello from Gotenberg</h1></body></html>";
content.Add(new StringContent(html), "files", "index.html");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("output.pdf", pdfBytes);
Console.WriteLine("PDF generated successfully");
}
}using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergExample
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
var html = "<html><body><h1>Hello from Gotenberg</h1></body></html>";
content.Add(new StringContent(html), "files", "index.html");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("output.pdf", pdfBytes);
Console.WriteLine("PDF generated successfully");
}
}(IronPDF 之後):
// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class IronPdfExample
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var html = "<html><body><h1>Hello from IronPDF</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF generated successfully");
}
}// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class IronPdfExample
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var html = "<html><body><h1>Hello from IronPDF</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF generated successfully");
}
}差異很大:Gotenberg 需要建置HttpClient ,建置MultipartFormDataContent ,向正在執行的 Docker 容器發出非同步 HTTP POST 請求,並處理位元組陣列回應。 IronPDF 將其簡化為三行程式碼,透過ChromePdfRenderer方法呼叫實現——沒有網路開銷,沒有容器依賴,沒有非同步複雜性。 有關其他渲染選項,請參閱HTML 轉 PDF 文件。
範例 2:URL 轉 PDF
之前(哥德堡):
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergUrlToPdf
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/url";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
content.Add(new StringContent("https://example.com"), "url");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("webpage.pdf", pdfBytes);
Console.WriteLine("PDF from URL generated successfully");
}
}using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergUrlToPdf
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/url";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
content.Add(new StringContent("https://example.com"), "url");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("webpage.pdf", pdfBytes);
Console.WriteLine("PDF from URL generated successfully");
}
}(IronPDF 之後):
// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class IronPdfUrlToPdf
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://example.com");
pdf.SaveAs("webpage.pdf");
Console.WriteLine("PDF from URL generated successfully");
}
}// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class IronPdfUrlToPdf
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://example.com");
pdf.SaveAs("webpage.pdf");
Console.WriteLine("PDF from URL generated successfully");
}
}Gotenberg 方法需要一個不同的端點( /forms/chromium/convert/url ),使用 URL 作為表單欄位建立多部分內容,並處理非同步 HTTP 回應。 IronPDF 的RenderUrlAsPdf()方法直接接受 URL,並同步回傳一個PdfDocument物件。 了解更多關於URL轉PDF的資訊。
範例 3:自訂紙張尺寸和邊距
之前(哥德堡):
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergCustomSize
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
var html = "<html><body><h1>Custom Size PDF</h1></body></html>";
content.Add(new StringContent(html), "files", "index.html");
content.Add(new StringContent("8.5"), "paperWidth");
content.Add(new StringContent("11"), "paperHeight");
content.Add(new StringContent("0.5"), "marginTop");
content.Add(new StringContent("0.5"), "marginBottom");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("custom-size.pdf", pdfBytes);
Console.WriteLine("Custom size PDF generated successfully");
}
}using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergCustomSize
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
var html = "<html><body><h1>Custom Size PDF</h1></body></html>";
content.Add(new StringContent(html), "files", "index.html");
content.Add(new StringContent("8.5"), "paperWidth");
content.Add(new StringContent("11"), "paperHeight");
content.Add(new StringContent("0.5"), "marginTop");
content.Add(new StringContent("0.5"), "marginBottom");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("custom-size.pdf", pdfBytes);
Console.WriteLine("Custom size PDF generated successfully");
}
}(IronPDF 之後):
// NuGet: Install-Package IronPdf
using System;
using IronPdf;
using IronPdf.Rendering;
class IronPdfCustomSize
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter;
renderer.RenderingOptions.MarginTop = 50;
renderer.RenderingOptions.MarginBottom = 50;
var html = "<html><body><h1>Custom Size PDF</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("custom-size.pdf");
Console.WriteLine("Custom size PDF generated successfully");
}
}// NuGet: Install-Package IronPdf
using System;
using IronPdf;
using IronPdf.Rendering;
class IronPdfCustomSize
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter;
renderer.RenderingOptions.MarginTop = 50;
renderer.RenderingOptions.MarginBottom = 50;
var html = "<html><body><h1>Custom Size PDF</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("custom-size.pdf");
Console.WriteLine("Custom size PDF generated successfully");
}
}Gotenberg 要求在 multipart 表單資料中加入基於字串的參數( "8.5" 、 "11" 、 "0.5" ),沒有型別安全,沒有 IntelliSense,容易輸入錯誤。 IronPDF 提供具有PdfPaperSize枚舉和數值邊距值的強型別屬性。 請注意,IronPDF 的邊距單位是毫米(50 毫米 ≈ 2 英吋),而 哥登堡 使用英吋。
關鍵遷移說明
單位換算
哥登堡遷移中最重要的轉換是邊距單位:
// Gotenberg: margins in inches
content.Add(new StringContent("0.5"), "marginTop"); // 0.5 inches
content.Add(new StringContent("1"), "marginBottom"); // 1 inch
// IronPDF: margins in millimeters
renderer.RenderingOptions.MarginTop = 12.7; // 0.5 inches × 25.4 = 12.7mm
renderer.RenderingOptions.MarginBottom = 25.4; // 1 inch × 25.4 = 25.4mm// Gotenberg: margins in inches
content.Add(new StringContent("0.5"), "marginTop"); // 0.5 inches
content.Add(new StringContent("1"), "marginBottom"); // 1 inch
// IronPDF: margins in millimeters
renderer.RenderingOptions.MarginTop = 12.7; // 0.5 inches × 25.4 = 12.7mm
renderer.RenderingOptions.MarginBottom = 25.4; // 1 inch × 25.4 = 25.4mm換算公式: millimeters = inches × 25.4
同步與非同步
由於 哥登堡 使用 HTTP 通信,因此需要非同步操作:
// Gotenberg: Forced async due to network calls
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
// IronPDF: Synchronous in-process execution
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
// IronPDF: Async wrapper if needed
var pdf = await Task.Run(() => renderer.RenderHtmlAsPdf(html));// Gotenberg: Forced async due to network calls
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
// IronPDF: Synchronous in-process execution
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
// IronPDF: Async wrapper if needed
var pdf = await Task.Run(() => renderer.RenderHtmlAsPdf(html));錯誤處理
// Gotenberg: HTTP error handling
try
{
var response = await client.PostAsync(gotenbergUrl, content);
response.EnsureSuccessStatusCode(); // What if 500? 503? Timeout?
}
catch (HttpRequestException ex) { /* Network error */ }
catch (TaskCanceledException ex) { /* Timeout */ }
// IronPDF: Standard .NET exceptions
try
{
var pdf = renderer.RenderHtmlAsPdf(html);
}
catch (Exception ex)
{
Console.WriteLine($"PDF generation failed: {ex.Message}");
}// Gotenberg: HTTP error handling
try
{
var response = await client.PostAsync(gotenbergUrl, content);
response.EnsureSuccessStatusCode(); // What if 500? 503? Timeout?
}
catch (HttpRequestException ex) { /* Network error */ }
catch (TaskCanceledException ex) { /* Timeout */ }
// IronPDF: Standard .NET exceptions
try
{
var pdf = renderer.RenderHtmlAsPdf(html);
}
catch (Exception ex)
{
Console.WriteLine($"PDF generation failed: {ex.Message}");
}基礎設施拆除
遷移完成後,請從您的基礎架構中移除 Gotenberg:
# REMOVE from docker-compose.yml:
# services:
# gotenberg:
# image: gotenberg/gotenberg:8
# ports:
# - "3000:3000"
# deploy:
# resources:
# limits:
# memory: 2G# REMOVE from docker-compose.yml:
# services:
# gotenberg:
# image: gotenberg/gotenberg:8
# ports:
# - "3000:3000"
# deploy:
# resources:
# limits:
# memory: 2G性能考量
延遲比較
| 手術 | 哥登堡(溫暖) | 哥登堡(冷啟動) | IronPDF(初稿) | IronPDF(後續) |
|---|---|---|---|---|
| 簡單的 HTML | 150-300毫秒 | 2-5秒 | 1-2秒 | 50-150毫秒 |
| 複雜的 HTML | 500-1500毫秒 | 3-7秒 | 1.5-3秒 | 200-800毫秒 |
| URL渲染 | 1-5秒 | 3-10秒 | 1-5秒 | 500毫秒-3秒 |
基礎設施成本消除
| 資源 | 哥登堡 | IronPDF |
|---|---|---|
| 所需容器 | 1-N(縮放) | 0 |
| 每個容器的內存 | 512MB-2GB | 不適用 |
| 每個請求的網路開銷 | 10-100毫秒 | 0毫秒 |
| 健康檢查終點 | 必需的 | 不需要 |
| 負載平衡器 | 經常需要 | 不需要 |
故障排除
問題 1:無需使用 HttpClient 模式
問題:程式碼仍然使用HttpClient和MultipartFormDataContent 。
解決方案:完全替換為ChromePdfRenderer :
// Remove all of this:
// using var client = new HttpClient();
// using var content = new MultipartFormDataContent();
// content.Add(new StringContent(html), "files", "index.html");
// var response = await client.PostAsync(url, content);
// Replace with:
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);// Remove all of this:
// using var client = new HttpClient();
// using var content = new MultipartFormDataContent();
// content.Add(new StringContent(html), "files", "index.html");
// var response = await client.PostAsync(url, content);
// Replace with:
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);問題 2:利潤單位錯誤
問題:遷移後 PDF 檔案的邊距不正確。
解決方法:將英吋轉換為毫米:
// 哥登堡 used inches: "0.5"
// IronPDF uses millimeters: 0.5 × 25.4 = 12.7
renderer.RenderingOptions.MarginTop = 12.7;// 哥登堡 used inches: "0.5"
// IronPDF uses millimeters: 0.5 × 25.4 = 12.7
renderer.RenderingOptions.MarginTop = 12.7;問題 3:容器 URL 引用
問題:程式碼包含http://gotenberg:3000或類似 URL。
解決方案:移除所有容器 URL 引用-IronPDF 以進程內方式執行:
// Remove:
// private readonly string _gotenbergUrl = "http://gotenberg:3000";
// IronPDF needs no URL - it's in-process
var renderer = new ChromePdfRenderer();// Remove:
// private readonly string _gotenbergUrl = "http://gotenberg:3000";
// IronPDF needs no URL - it's in-process
var renderer = new ChromePdfRenderer();遷移清單
遷移前
- 清點程式碼庫中所有 哥登堡 HTTP 調用
- 記錄目前 哥登堡 配置(逾時、頁邊距、紙張尺寸)
- 識別所有 Docker/Kubernetes 哥登堡 配置
- 取得 IronPDF 許可證密鑰
- 規劃基礎建設退役
程式碼遷移
安裝 IronPdf NuGet 套件: dotnet add package IronPdf
- 移除 哥登堡 用戶端軟體包
- 將所有對 哥登堡 的 HTTP 呼叫替換為 IronPDF 方法調用
- 將邊距單位從英吋轉換為毫米
- 更新錯誤處理(HTTP 錯誤 → .NET 異常)
- 新增啟動時許可證金鑰初始化功能
基礎設施遷移
- 從 Docker Compose/Kubernetes 移除 Gotenberg
- 更新 CI/CD 管線(移除 哥登堡 鏡像拉取)
- 移除哥德堡健康檢查
- 從設定中移除 哥登堡 URL
測試
- 測試 HTML 到 PDF 的轉換
- 測試 URL 到 PDF 的轉換
- 核實邊距和尺寸準確性
- 負載下的效能測試
- 測試首次渲染預熱時間
移民後
- 移除 哥登堡 容器部署
- 歸檔 哥登堡 設定檔
- 更新文檔
- 監控應用程式記憶體使用情況
- 檢查是否有孤立的網路連接






