跳至页脚内容
视频

如何在Blazor服务器中使用C#将Razor转换为PDF

从Kaizen.io HTML-to-PDF迁移到IronPDF,用一个通过HTTP暴露的自托管Docker容器替换为一个内嵌的.NET库。Kaizen.io HTML 到 PDF仅作为 Docker 映像 kaizenio.azurecr.io/html-to-pdf 提供,并在端口 8080 上暴露一个 REST 端点 POST /html-to-pdf — 没有官方 .NET SDK 或 NuGet 包,因此每个 C# 调用都必须针对正在运行的容器进行手动实现 HttpClient。 本指南介绍了用IronPDF的 ChromePdfRenderer 替换该模式。

为什么要从 Kaizen.io 迁移到 IronPDF.

容器-API挑战

Kaizen.io HTML-to-PDF 是一个 Docker 容器,拥有一个特意保持小规模的 v1.x API,而 C# 集成方式是基于您自己在 HttpClient 之上构建的内容。 该形状在生产中有真实的限制:

  1. 运行容器:您需要运行、监控和更新在应用程序可访问的地方的 kaizenio.azurecr.io/html-to-pdf:latest — 本地 Docker、sidecar 或独立主机。

  2. 没有 .NET SDK:每个 C# 调用都是手动实现的 HttpClient POST + JSON。 没有IntelliSense,没有请求形状的编译时检查。

  3. 小型 v1.x API 接口:文档记录的 JSON 请求体仅接受一个 html 字段。 URL-to-PDF,自定义样式表,页眉/页脚,页面大小,方向和边距被列为路线图项目而不是发布的功能 — 除了渲染 HTML 字符串之外的任何内容都必须在 HTML 内部表达,通常通过 @page CSS 和绝对定位的 div。

  4. 不支持页码:API 没有 {page}/ {total}占位符,因此无法在服务器端生成"第 X 页,共 Y 页"页脚。

  5. 每个 PDF 的 HTTP 往返:即使容器在 localhost 上运行,每个 PDF 都需要支付 JSON 序列化和网络跳跃的成本。

  6. 免费层的水印:如果没有在容器上设置 KAIZEN_PDF_LICENSE 环境变量,输出就会有水印。

Kaizen.io 与IronPDF对比

特征 Kaizen.io HTML 到 PDF IronPDF
分发 Docker 映像 kaizenio.azurecr.io/html-to-pdf NuGet IronPdf
C#集成 手动实现的 HttpClient POST (没有 SDK) 强类型的 ChromePdfRenderer API
进程模型 进程外容器 翻译中
端点界面 (v1.x) POST /html-to-pdf with { "html": ... } HTML、文件、URL的方法
URL输入 路线图 RenderUrlAsPdf(url)
页眉/页脚 不在v1.x API中; 通过固定位置CSS伪造 TextHeader/Footer and HtmlHeader/Footer
页码 不支持 {page}and {total-pages}placeholders
页面大小/方向 在 HTML 中嵌入 @page CSS RenderingOptions.PaperSize 等。
许可 一次性许可证; 带水印的免费层 商业(年度或永久)

对于标准化现代.NET的团队,IronPDF从请求路径中移除边车容器和HTTP跳,暴露强类型的配置界面。


迁移复杂性评估

按功能估算的工作量

特征 迁移复杂性
基本 HTML 到 PDF 极低
HTML 文件到 PDF 极低
URL 至 PDF 低(Kaizen v1.x没有URL端点——解决方案整体替换)
页眉/页脚 中(伪CSS divs替换为真实的页眉区域)
页码 新功能(在Kaizen v1.x中不可用)
页面设置 低 (@page CSS moves to RenderingOptions)

范式转换

基本的转变是从到Docker容器的进程外HTTP调用进程内渲染

Kaizen.io:  HttpClient.PostAsync("http://.../html-to-pdf", { html }) → byte[]
IronPDF:    ChromePdfRenderer → RenderHtmlAsPdf(html) → PdfDocument

开始之前

前提条件

  1. .NET环境: .NET Framework 4.6.2+或.NET Core 3.1+ / .NET 5+
  2. NuGet 访问权限:能够安装 NuGet 包
  3. IronPDF 许可证:请从ironpdf.com获取您的许可证密钥。

软件包变更

没有可移除的Kaizen NuGet包——Kaizen仅作为Docker映像提供。 停止容器并添加IronPDF包:

# Stop and remove the running Kaizen container (if any)
docker stop kaizen-pdf
docker rm kaizen-pdf

# Install IronPDF
dotnet add package IronPdf
# Stop and remove the running Kaizen container (if any)
docker stop kaizen-pdf
docker rm kaizen-pdf

# Install IronPDF
dotnet add package IronPdf
SHELL

许可配置

// Add at application startup (Program.cs or Startup.cs)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Add at application startup (Program.cs or Startup.cs)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
' Add at application startup (Program.vb or Startup.vb)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

确定 Kaizen.io 的用法

因为 Kaizen 没有 SDK,调用它看起来像通用的 HttpClient POST。 搜索端点、映像名和许可证环境变量而不是命名空间:

grep -r "html-to-pdf\|KAIZEN_PDF_LICENSE\|kaizenio.azurecr.io\|localhost:8080" \
  --include="*.cs" --include="*.json" --include="*.yml" .
grep -r "html-to-pdf\|KAIZEN_PDF_LICENSE\|kaizenio.azurecr.io\|localhost:8080" \
  --include="*.cs" --include="*.json" --include="*.yml" .
SHELL

完整的 API 参考

概念映射

没有需要映射的Kaizen .NET类——只有JSON请求形状和您围绕它构建的约定。

Kaizen.io概念 IronPDF 同等产品
HttpClient + POST /html-to-pdf ChromePdfRenderer
JSON { "html": "..." }请求体 RenderHtmlAsPdf(string html)
(No URL field in v1.x) RenderUrlAsPdf(string url)
(No file field in v1.x) RenderHtmlFileAsPdf(string path)
内联 @page CSS 用于尺寸 RenderingOptions.PaperSize
内联 @page CSS 用于方向 RenderingOptions.PaperOrientation
内嵌 @page { margin: ... } RenderingOptions.MarginTop/Bottom/Left/Right
固定定位的 <div class='header'> hack RenderingOptions.TextHeader / HtmlHeader
固定定位的 <div class='footer'> hack RenderingOptions.TextFooter / HtmlFooter
HttpClient.PostAsync RenderHtmlAsPdfAsync
容器环境变量 KAIZEN_PDF_LICENSE IronPdf.License.LicenseKey
HTTP byte[] 响应 pdf.BinaryData / pdf.SaveAs(path)

占位符映射

Kaizen v1.x没有服务器端占位符。 如果您以前在POST之前手动替换HTML中的字符串,请切换到IronPDF的渲染时占位符:

您之前用的方法 IronPDF 占位符
html.Replace("{page}", currentPage.ToString()) {page}
html.Replace("{total}", total.ToString()) {total-pages}
html.Replace("{date}", DateTime.Now.ToShortDateString()) {date}
html.Replace("{title}", docTitle) {html-title}

代码迁移示例

示例 1:将基本 HTML 转换为 PDF.

之前(Kaizen.io——将JSON POST到容器):

// Container must be running:
//   docker run -d -p 8080:8080 -e KAIZEN_PDF_LICENSE=... \
//     kaizenio.azurecr.io/html-to-pdf:latest
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        using var http = new HttpClient();
        var payload = JsonSerializer.Serialize(new { html = "<html><body><h1>Hello World</h1></body></html>" });
        var content = new StringContent(payload, Encoding.UTF8, "application/json");
        var response = await http.PostAsync("http://localhost:8080/html-to-pdf", content);
        response.EnsureSuccessStatusCode();
        var pdfBytes = await response.Content.ReadAsByteArrayAsync();
        File.WriteAllBytes("output.pdf", pdfBytes);
    }
}
// Container must be running:
//   docker run -d -p 8080:8080 -e KAIZEN_PDF_LICENSE=... \
//     kaizenio.azurecr.io/html-to-pdf:latest
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        using var http = new HttpClient();
        var payload = JsonSerializer.Serialize(new { html = "<html><body><h1>Hello World</h1></body></html>" });
        var content = new StringContent(payload, Encoding.UTF8, "application/json");
        var response = await http.PostAsync("http://localhost:8080/html-to-pdf", content);
        response.EnsureSuccessStatusCode();
        var pdfBytes = await response.Content.ReadAsByteArrayAsync();
        File.WriteAllBytes("output.pdf", pdfBytes);
    }
}
Imports System.IO
Imports System.Net.Http
Imports System.Text
Imports System.Text.Json
Imports System.Threading.Tasks

Module Program
    Async Function Main() As Task
        Using http As New HttpClient()
            Dim payload = JsonSerializer.Serialize(New With {.html = "<html><body><h1>Hello World</h1></body></html>"})
            Dim content As New StringContent(payload, Encoding.UTF8, "application/json")
            Dim response = Await http.PostAsync("http://localhost:8080/html-to-pdf", content)
            response.EnsureSuccessStatusCode()
            Dim pdfBytes = Await response.Content.ReadAsByteArrayAsync()
            File.WriteAllBytes("output.pdf", pdfBytes)
        End Using
    End Function
End Module
$vbLabelText   $csharpLabel

After (IronPDF):

// NuGet: Install-Package IronPdf
using IronPdf;
using System.IO;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var html = "<html><body><h1>Hello World</h1></body></html>";
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("output.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System.IO;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var html = "<html><body><h1>Hello World</h1></body></html>";
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("output.pdf");
    }
}
Imports IronPdf
Imports System.IO

Class Program
    Shared Sub Main()
        Dim renderer = New ChromePdfRenderer()
        Dim html = "<html><body><h1>Hello World</h1></body></html>"
        Dim pdf = renderer.RenderHtmlAsPdf(html)
        pdf.SaveAs("output.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

Kaizen.io的方法是序列化JSON,将其发布到容器的REST端点,检查状态码,将响应读取为字节,并将这些字节写入磁盘。IronPDF的 ChromePdfRenderer 在进程内运行 — RenderHtmlAsPdf() 返回一个带有 PdfDocument 方法的 SaveAs(),因此往返和手动字节管理消失了。 有关其他渲染选项,请参阅 HTML to PDF 文档

示例 2:使用页面设置将 HTML 文件转换为 PDF 文件

Kaizen v1.x 没有文件端点和页面布局字段 — 您自己读取文件并在 @page CSS 中嵌入页面大小/方向。

之前 (Kaizen.io):

using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var body = File.ReadAllText("input.html");
        var html = "<style>@page { size: A4 portrait; }</style>" + body;

        using var http = new HttpClient();
        var payload = JsonSerializer.Serialize(new { html });
        var response = await http.PostAsync(
            "http://localhost:8080/html-to-pdf",
            new StringContent(payload, Encoding.UTF8, "application/json"));
        response.EnsureSuccessStatusCode();
        File.WriteAllBytes("document.pdf", await response.Content.ReadAsByteArrayAsync());
    }
}
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var body = File.ReadAllText("input.html");
        var html = "<style>@page { size: A4 portrait; }</style>" + body;

        using var http = new HttpClient();
        var payload = JsonSerializer.Serialize(new { html });
        var response = await http.PostAsync(
            "http://localhost:8080/html-to-pdf",
            new StringContent(payload, Encoding.UTF8, "application/json"));
        response.EnsureSuccessStatusCode();
        File.WriteAllBytes("document.pdf", await response.Content.ReadAsByteArrayAsync());
    }
}
Imports System.IO
Imports System.Net.Http
Imports System.Text
Imports System.Text.Json
Imports System.Threading.Tasks

Module Program
    Async Function Main() As Task
        Dim body = File.ReadAllText("input.html")
        Dim html = "<style>@page { size: A4 portrait; }</style>" & body

        Using http As New HttpClient()
            Dim payload = JsonSerializer.Serialize(New With {Key .html = html})
            Dim response = Await http.PostAsync(
                "http://localhost:8080/html-to-pdf",
                New StringContent(payload, Encoding.UTF8, "application/json"))
            response.EnsureSuccessStatusCode()
            File.WriteAllBytes("document.pdf", Await response.Content.ReadAsByteArrayAsync())
        End Using
    End Function
End Module
$vbLabelText   $csharpLabel

After (IronPDF):

// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
        renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Portrait;
        var pdf = renderer.RenderHtmlFileAsPdf("input.html");
        pdf.SaveAs("document.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
        renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Portrait;
        var pdf = renderer.RenderHtmlFileAsPdf("input.html");
        pdf.SaveAs("document.pdf");
    }
}
Imports IronPdf

Class Program
    Shared Sub Main()
        Dim renderer = New ChromePdfRenderer()
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
        renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Portrait
        Dim pdf = renderer.RenderHtmlFileAsPdf("input.html")
        pdf.SaveAs("document.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

RenderHtmlFileAsPdf() 直接读取文件,并且页面大小和方向从内联 @page CSS 移到 RenderingOptions 属性。

示例 3:带页眉和页脚的 URL 至 PDF 文件

Kaizen v1.x 没有 ConvertUrl,没有页眉/页脚字段,也没有页码占位符。 解决办法是自己获取页面并用 @page CSS 和固定定位的 div 包裹以伪造页眉/页脚 — 无法渲染页码。

之前 (Kaizen.io):

using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        using var http = new HttpClient();
        var page = await http.GetStringAsync("https://example.com");
        var html = $@"<!doctype html><html><head><style>
            @page {{margin: 20mm;}}
            .h {{position: fixed; top: -15mm; left: 0; right: 0; text-align: center;}}
            .f {{position: fixed; bottom: -15mm; left: 0; right: 0; text-align: center;}}
        </style></head><body>
            <div class='h'>Company Header</div>
            <div class='f'>Footer (page numbers unsupported in Kaizen v1.x)</div>
            {page}
        </body></html>";

        var payload = JsonSerializer.Serialize(new { html });
        var response = await http.PostAsync(
            "http://localhost:8080/html-to-pdf",
            new StringContent(payload, Encoding.UTF8, "application/json"));
        response.EnsureSuccessStatusCode();
        File.WriteAllBytes("webpage.pdf", await response.Content.ReadAsByteArrayAsync());
    }
}
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        using var http = new HttpClient();
        var page = await http.GetStringAsync("https://example.com");
        var html = $@"<!doctype html><html><head><style>
            @page {{margin: 20mm;}}
            .h {{position: fixed; top: -15mm; left: 0; right: 0; text-align: center;}}
            .f {{position: fixed; bottom: -15mm; left: 0; right: 0; text-align: center;}}
        </style></head><body>
            <div class='h'>Company Header</div>
            <div class='f'>Footer (page numbers unsupported in Kaizen v1.x)</div>
            {page}
        </body></html>";

        var payload = JsonSerializer.Serialize(new { html });
        var response = await http.PostAsync(
            "http://localhost:8080/html-to-pdf",
            new StringContent(payload, Encoding.UTF8, "application/json"));
        response.EnsureSuccessStatusCode();
        File.WriteAllBytes("webpage.pdf", await response.Content.ReadAsByteArrayAsync());
    }
}
Imports System.IO
Imports System.Net.Http
Imports System.Text
Imports System.Text.Json
Imports System.Threading.Tasks

Module Program
    Async Function Main() As Task
        Using http As New HttpClient()
            Dim page As String = Await http.GetStringAsync("https://example.com")
            Dim html As String = $"<!doctype html><html><head><style>
                @page {{margin: 20mm;}}
                .h {{position: fixed; top: -15mm; left: 0; right: 0; text-align: center;}}
                .f {{position: fixed; bottom: -15mm; left: 0; right: 0; text-align: center;}}
            </style></head><body>
                <div class='h'>Company Header</div>
                <div class='f'>Footer (page numbers unsupported in Kaizen v1.x)</div>
                {page}
            </body></html>"

            Dim payload As String = JsonSerializer.Serialize(New With {Key .html = html})
            Dim response As HttpResponseMessage = Await http.PostAsync(
                "http://localhost:8080/html-to-pdf",
                New StringContent(payload, Encoding.UTF8, "application/json"))
            response.EnsureSuccessStatusCode()
            File.WriteAllBytes("webpage.pdf", Await response.Content.ReadAsByteArrayAsync())
        End Using
    End Function
End Module
$vbLabelText   $csharpLabel

After (IronPDF):

// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.TextHeader.CenterText = "Company Header";
        renderer.RenderingOptions.TextFooter.CenterText = "Page {page} of {total-pages}";
        renderer.RenderingOptions.MarginTop = 20;
        renderer.RenderingOptions.MarginBottom = 20;
        var pdf = renderer.RenderUrlAsPdf("https://example.com");
        pdf.SaveAs("webpage.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.TextHeader.CenterText = "Company Header";
        renderer.RenderingOptions.TextFooter.CenterText = "Page {page} of {total-pages}";
        renderer.RenderingOptions.MarginTop = 20;
        renderer.RenderingOptions.MarginBottom = 20;
        var pdf = renderer.RenderUrlAsPdf("https://example.com");
        pdf.SaveAs("webpage.pdf");
    }
}
Imports IronPdf

Class Program
    Shared Sub Main()
        Dim renderer = New ChromePdfRenderer()
        renderer.RenderingOptions.TextHeader.CenterText = "Company Header"
        renderer.RenderingOptions.TextFooter.CenterText = "Page {page} of {total-pages}"
        renderer.RenderingOptions.MarginTop = 20
        renderer.RenderingOptions.MarginBottom = 20
        Dim pdf = renderer.RenderUrlAsPdf("https://example.com")
        pdf.SaveAs("webpage.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

RenderUrlAsPdf() 直接获取并渲染 URL — 没有客户端页面获取 — 伪造的固定定位的 div 被 TextHeader / TextFooter 区域替换。 页码通过 {page}{total-pages}占位符生成,而 Kaizen v1.x 没有提供此功能。了解更多关于URL 到 PDF 转换页眉和页脚


关键迁移说明

许可证存在于代码中,而不是容器中

Kaizen 的许可证通过 Docker 容器上的 KAIZEN_PDF_LICENSE 环境变量配置。 IronPDF的许可证是一个静态属性,在应用程序启动时设置一次:

// DELETE the Kaizen container env var:
//   docker run ... -e KAIZEN_PDF_LICENSE=... kaizenio.azurecr.io/html-to-pdf

// IronPDF: set once at startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
var renderer = new ChromePdfRenderer();
// DELETE the Kaizen container env var:
//   docker run ... -e KAIZEN_PDF_LICENSE=... kaizenio.azurecr.io/html-to-pdf

// IronPDF: set once at startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
var renderer = new ChromePdfRenderer();
' DELETE the Kaizen container env var:
'   docker run ... -e KAIZEN_PDF_LICENSE=... kaizenio.azurecr.io/html-to-pdf

' IronPDF: set once at startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim renderer As New ChromePdfRenderer()
$vbLabelText   $csharpLabel

占位符语法

如果您以前在POST之前手动替换HTML中的字符串,请切换到IronPDF的渲染时占位符:

  • {page}(不变)
  • {total}{total-pages}
  • {title}{html-title}
  • {date}{date}(不变)

返回类型更改

Kaizen 通过 HTTP 返回原始字节。IronPDF 返回一个 PdfDocument

// Kaizen.io returns byte[] via HTTP
byte[] pdfBytes = await response.Content.ReadAsByteArrayAsync();
File.WriteAllBytes("output.pdf", pdfBytes);

//IronPDFreturns PdfDocument
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");           // Direct save
byte[] bytes = pdf.BinaryData;      // Or get bytes if needed
// Kaizen.io returns byte[] via HTTP
byte[] pdfBytes = await response.Content.ReadAsByteArrayAsync();
File.WriteAllBytes("output.pdf", pdfBytes);

//IronPDFreturns PdfDocument
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");           // Direct save
byte[] bytes = pdf.BinaryData;      // Or get bytes if needed
Imports System.IO

' Kaizen.io returns Byte() via HTTP
Dim pdfBytes As Byte() = Await response.Content.ReadAsByteArrayAsync()
File.WriteAllBytes("output.pdf", pdfBytes)

' IronPDF returns PdfDocument
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")           ' Direct save
Dim bytes As Byte() = pdf.BinaryData ' Or get bytes if needed
$vbLabelText   $csharpLabel

删除HTTP管道

一旦渲染器在进程内,支持代码就会消失:

// DELETE all of:
// - HttpClient lifetime management
// - JSON serialization of { html }
// - response.EnsureSuccessStatusCode() / status-code branches
// - "container unreachable" retry/backoff
// - ReadAsByteArrayAsync()

// Replaced with a single in-process call:
var pdf = renderer.RenderHtmlAsPdf(html);
// DELETE all of:
// - HttpClient lifetime management
// - JSON serialization of { html }
// - response.EnsureSuccessStatusCode() / status-code branches
// - "container unreachable" retry/backoff
// - ReadAsByteArrayAsync()

// Replaced with a single in-process call:
var pdf = renderer.RenderHtmlAsPdf(html);
$vbLabelText   $csharpLabel

故障排除

问题1:没有HtmlToPdfConverter类

问题:没有 HtmlToPdfConverter 类可以交换 — Kaizen 根本没有 .NET SDK。

解决方案:迁移是从 HttpClient POSTs 针对容器到 ChromePdfRenderer

// Kaizen.io: hand-rolled HTTP
using var http = new HttpClient();
var response = await http.PostAsync("http://localhost:8080/html-to-pdf", content);

// IronPDF: in-process renderer
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
// Kaizen.io: hand-rolled HTTP
using var http = new HttpClient();
var response = await http.PostAsync("http://localhost:8080/html-to-pdf", content);

// IronPDF: in-process renderer
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
Imports System.Net.Http
Imports IronPdf

' Kaizen.io: hand-rolled HTTP
Using http As New HttpClient()
    Dim response = Await http.PostAsync("http://localhost:8080/html-to-pdf", content)
End Using

' IronPDF: in-process renderer
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(html)
$vbLabelText   $csharpLabel

问题2:选项对象去了哪里?

问题:Kaizen v1.x 没有 ConversionOptions — 页面布局是内联 @page CSS,页眉/页脚是固定定位的 div。

解决方案:将该配置移动到渲染器的 RenderingOptions 上:

// Before: <style>@page { size: A4 portrait; margin: 20mm; }</style>
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Portrait;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
// Before: <style>@page { size: A4 portrait; margin: 20mm; }</style>
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Portrait;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
' Before: <style>@page { size: A4 portrait; margin: 20mm; }</style>
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Portrait
renderer.RenderingOptions.MarginTop = 20
renderer.RenderingOptions.MarginBottom = 20
$vbLabelText   $csharpLabel

问题3:页码无法呈现

问题:Kaizen v1.x 没有 {page}/ {total}占位符支持,因此任何迁移前的"第 X 页,共 Y 页"页脚要么缺失,要么是静态文本。

解决方案: 使用IronPDF的页眉/页脚占位符:

renderer.RenderingOptions.TextFooter = new TextHeaderFooter
{
    CenterText = "Page {page} of {total-pages}"
};
renderer.RenderingOptions.TextFooter = new TextHeaderFooter
{
    CenterText = "Page {page} of {total-pages}"
};
renderer.RenderingOptions.TextFooter = New TextHeaderFooter With {
    .CenterText = "Page {page} of {total-pages}"
}
$vbLabelText   $csharpLabel

如果您之前在自己代码中手动替换了 {total}并在发送POST请求之前,请移除该替换 —IronPDF会在渲染时解析 {total-pages}

问题4:容器连接错误

问题: 代码路径处理"容器无法访问"/端口-8080错误。

解决方案: IronPDF在进程中运行——没有要连接的端点。 删除连接错误处理。

问题 5:首次渲染缓慢

问题:首次生成 PDF 文件需要 1-3 秒。

解决方案:IronPDF会在首次使用时初始化 Chromium。 在应用程序启动时预热:

// In Program.cs or Startup.cs:
new ChromePdfRenderer().RenderHtmlAsPdf("<html></html>");
// In Program.cs or Startup.cs:
new ChromePdfRenderer().RenderHtmlAsPdf("<html></html>");
' In Program.vb or Startup.vb:
Call New ChromePdfRenderer().RenderHtmlAsPdf("<html></html>")
$vbLabelText   $csharpLabel

迁移清单

迁移前

  • 定位每个 Kaizen 调用点(搜索 html-to-pdf, KAIZEN_PDF_LICENSE, kaizenio.azurecr.io, localhost:8080
  • 文档化用于尺寸、方向、边距的内联 @page CSS
  • 文档伪造的页眉/页脚div(固定位置且有负偏移)
  • 列出任何客户端占位符替换 (html.Replace("{page}", ...) 等)
  • 注意容器生命周期:拉取、运行、重启、许可环境变量
  • 获取IronPDF许可证密钥

容器拆解

  • 停止并移除运行中的 Kaizen 容器 (docker stop kaizen-pdf && docker rm kaizen-pdf)
  • 从CI/CD中移除Kaizen的拉取/运行步骤
  • 从 secrets/env 中移除 KAIZEN_PDF_LICENSE
  • 安装 IronPdf NuGet 包 (dotnet add package IronPdf)

代码更改

  • 在启动时添加许可证密钥配置
  • HttpClient POST 替换为 ChromePdfRenderer
  • 将嵌入的 @page CSS 移入 RenderingOptions 属性
  • 将 JSON POST 替换为 RenderHtmlAsPdf() / RenderHtmlFileAsPdf() / RenderUrlAsPdf()
  • 将伪造的页眉/页脚 div 替换为 TextHeader/FooterHtmlHeader/Footer
  • 更新占位符语法 ({total}{total-pages}, {title}{html-title})
  • pdf.BinaryData 替换 byte[] HTTP 请求体
  • 使用 pdf.SaveAs() 代替 File.WriteAllBytes()
  • 删除容器可达性错误处理和重试/后退

测试

  • 测试所有 PDF 生成路径
  • 验证页眉/页脚渲染和页码(新功能)
  • 验证边距、页面大小和方向
  • 测试离线操作(不需要容器)

后迁移

  • 拆解Kaizen容器基础设施
  • 更新环境变量/秘密
  • 从监控/报警中移除容器健康检查
  • 文档记录新的类型化异常错误模式

请注意Kaizen.io 是其各自所有者的注册商标。 本网站与Kaizen.io无关联,未被其认可或赞助。 所有产品名称、徽标和品牌均为各自所有者的财产。 比较仅供参考,反映撰写时公开可用的信息。

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。

钢铁支援团队

我们每周 5 天,每天 24 小时在线。
聊天
电子邮件
打电话给我