如何使用C#将DOCX转换为PDF
Haukcode.DinkToPdf是曾经流行的DinkToPdf库的社区分叉,该库包装了wkhtmltopdf二进制文件,用于将HTML转换为.NET应用程序的PDF。 该分支后更名为Haukcode.WkHtmlToPdfDotNet,最新版本1.5.95于2024年10月22日发布,遵循LGPL-3.0-or-later。 虽然该分支在原始DinkToPdf(1.0.8,2017年4月18日)被弃用后,将包留在了NuGet上,但它仍然绑定到与其父相同的存档wkhtmltopdf二进制文件。 wkhtmltopdf/wkhtmltopdf 仓库于2023年1月2日被存档,整个wkhtmltopdf GitHub组织于2024年7月10日被存档,因此上游问题将不会被修补。
本指南提供了从Haukcode.DinkToPdf / Haukcode.WkHtmlToPdfDotNet 迁移到IronPDF的方法,包括逐步指导、代码对比以及面向希望迁移出存档的wkhtmltopdf二进制文件的.NET开发人员的实际示例。
安全通告:CVE-2022-35583
Haukcode.DinkToPdf继承了针对其上游wkhtmltopdf二进制文件提出的安全通告:
CVE-2022-35583 — 针对wkhtmltopdf 0.12.6的SSRF通告
针对wkhtmltopdf 0.12.6(NVD中的CVSS评分为9.8)发布了一份服务器端请求伪造通告; 被上游wkhtmltopdf项目提出异议,认为这是应用端输入清理问题而非库漏洞。 无论如何,它不会被修补——上游已被存档。 在公开讨论中标记的典型曝光模式包括:
- 攻击向量:不受信任的HTML内容在转换期间可能导致渲染器获取内部资源
- AWS Metadata: 如果渲染器在EC2上运行,向
http://169.254.169.254的请求可能返回实例元数据。 - 内部网络访问:渲染主机可能能够访问内部服务
- Local File Inclusion: 通过
file://协议可以读取本地文件。
不期望有上游补丁——wkhtmltopdf库已于2023年1月2日存档,最后一次发布是2020年6月的0.12.6。
IronPDFvs Haukcode.DinkToPdf:功能比较
了解架构差异有助于技术决策者评估迁移投资:
| 方面 | Haukcode.DinkToPdf | IronPDF |
|---|---|---|
| 底层引擎 | wkhtmltopdf(QtWebKit分叉,约2015年) | 现代 Chromium |
| 安全状态 | CVE-2022-35583通告(未修补/上游有争议) | 没有已知的关键CVE |
| 项目状态 | 社区分叉; 上游wkhtmltopdf被存档 | 积极维护 |
| HTML5/CSS3 | 没有现代Flexbox/Grid | 完整的 CSS3 |
| JavaScript语言 | 有限、不一致 | 全面支持 |
| 本地二进制文件 | libwkhtmltox.dll/.so/.dylib 每个平台 |
已管理的NuGet包 |
| 线程安全 | SynchronizedConverter 序列化调用 |
线程安全设计 |
| 支持 | 社区 | 专业支持 |
| 更新 | 分叉最后发布1.5.95(2024年10月22日); 上游wkhtmltopdf 0.12.6(2020年6月) | 定期发布 |
| 许可 | LGPL-3.0-or-later(分叉)/ MIT(原版DinkToPdf) | 免费试用版商业版 |
快速入门:Haukcode.DinkToPdf 到IronPDF的迁移
迁移工作可以通过以下基本步骤立即开始。
步骤 1:删除 DinkToPdf 和本地二进制文件
删除 Haukcode.DinkToPdf NuGet 软件包:
# Remove NuGet packages
dotnet remove package DinkToPdf
dotnet remove package Haukcode.DinkToPdf
dotnet remove package Haukcode.WkHtmlToPdf-DotNet
# Remove NuGet packages
dotnet remove package DinkToPdf
dotnet remove package Haukcode.DinkToPdf
dotnet remove package Haukcode.WkHtmlToPdf-DotNet
从您的项目中删除本地二进制文件:
libwkhtmltox.dll(Windows)libwkhtmltox.so(Linux)libwkhtmltox.dylib(macOS)
步骤2:安装IronPDF
# Install IronPDF
dotnet add package IronPdf
# Install IronPDF
dotnet add package IronPdf
步骤 3:更新命名空间
用IronPDF替换 DinkToPdf 命名空间:
// Before (Haukcode.DinkToPdf)
using DinkToPdf;
using DinkToPdf.Contracts;
// After (IronPDF)
using IronPdf;
using IronPdf.Rendering; // For RenderingOptions
// Before (Haukcode.DinkToPdf)
using DinkToPdf;
using DinkToPdf.Contracts;
// After (IronPDF)
using IronPdf;
using IronPdf.Rendering; // For RenderingOptions
Imports IronPdf
Imports IronPdf.Rendering
步骤 4:初始化许可证
在应用程序启动时添加许可证初始化:
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
代码迁移示例
基本 HTML 到 PDF 的转换
最基本的操作揭示了这些 .NET PDF 库之间的复杂性差异。
Haukcode.DinkToPdf 方法:
// NuGet: Install-Package DinkToPdf
using DinkToPdf;
using DinkToPdf.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4,
},
Objects = {
new ObjectSettings() {
HtmlContent = "<html><body><h1>Hello World</h1></body></html>",
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("output.pdf", pdf);
}
}
// NuGet: Install-Package DinkToPdf
using DinkToPdf;
using DinkToPdf.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4,
},
Objects = {
new ObjectSettings() {
HtmlContent = "<html><body><h1>Hello World</h1></body></html>",
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("output.pdf", pdf);
}
}
Imports DinkToPdf
Imports DinkToPdf.Contracts
Imports System.IO
Module Program
Sub Main()
Dim converter = New SynchronizedConverter(New PdfTools())
Dim doc = New HtmlToPdfDocument() With {
.GlobalSettings = New GlobalSettings() With {
.ColorMode = ColorMode.Color,
.Orientation = Orientation.Portrait,
.PaperSize = PaperKind.A4
},
.Objects = New List(Of ObjectSettings) From {
New ObjectSettings() With {
.HtmlContent = "<html><body><h1>Hello World</h1></body></html>"
}
}
}
Dim pdf As Byte() = converter.Convert(doc)
File.WriteAllBytes("output.pdf", pdf)
End Sub
End Module
IronPDF 方法:
// NuGet: Install-Package IronPdf
using IronPdf;
using System.IO;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<html><body><h1>Hello World</h1></body></html>");
pdf.SaveAs("output.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System.IO;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<html><body><h1>Hello World</h1></body></html>");
pdf.SaveAs("output.pdf");
}
}
Imports IronPdf
Imports System.IO
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf("<html><body><h1>Hello World</h1></body></html>")
pdf.SaveAs("output.pdf")
End Sub
End Class
Haukcode.DinkToPdf需要使用File.WriteAllBytes()手动写入文件。
IronPDF将其简化为三行:创建SaveAs()方法。
有关 HTML 转 PDF 的高级应用场景,请参阅 HTML 转 PDF 指南。
将 URL 转换为 PDF
URL 到 PDF 的转换也显示出类似的模式差异。
Haukcode.DinkToPdf 方法:
// NuGet: Install-Package DinkToPdf
using DinkToPdf;
using DinkToPdf.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4,
},
Objects = {
new ObjectSettings() {
Page = "https://www.example.com",
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("webpage.pdf", pdf);
}
}
// NuGet: Install-Package DinkToPdf
using DinkToPdf;
using DinkToPdf.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4,
},
Objects = {
new ObjectSettings() {
Page = "https://www.example.com",
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("webpage.pdf", pdf);
}
}
Imports DinkToPdf
Imports DinkToPdf.Contracts
Imports System.IO
Module Program
Sub Main()
Dim converter = New SynchronizedConverter(New PdfTools())
Dim doc = New HtmlToPdfDocument() With {
.GlobalSettings = New GlobalSettings() With {
.ColorMode = ColorMode.Color,
.Orientation = Orientation.Portrait,
.PaperSize = PaperKind.A4
},
.Objects = New List(Of ObjectSettings) From {
New ObjectSettings() With {
.Page = "https://www.example.com"
}
}
}
Dim pdf As Byte() = converter.Convert(doc)
File.WriteAllBytes("webpage.pdf", pdf)
End Sub
End Module
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("webpage.pdf");
}
}
// 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("webpage.pdf");
}
}
Imports IronPdf
Imports System
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("webpage.pdf")
End Sub
End Class
Haukcode.DinkToPdf对URL使用相同的文档构建模式并使用ObjectSettings.Page。 IronPDF提供了专门的RenderUrlAsPdf()方法,清晰地表达了意图。
请浏览 URL to PDF 文档,了解身份验证和自定义页眉选项。
自定义页面设置
配置方向、纸张大小和页边距需要采用不同的方法。
Haukcode.DinkToPdf 方法:
// NuGet: Install-Package DinkToPdf
using DinkToPdf;
using DinkToPdf.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Landscape,
PaperSize = PaperKind.Letter,
Margins = new MarginSettings() { Top = 10, Bottom = 10, Left = 10, Right = 10 }
},
Objects = {
new ObjectSettings() {
HtmlContent = "<html><body><h1>Landscape Document</h1><p>Custom page settings</p></body></html>",
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("landscape.pdf", pdf);
}
}
// NuGet: Install-Package DinkToPdf
using DinkToPdf;
using DinkToPdf.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Landscape,
PaperSize = PaperKind.Letter,
Margins = new MarginSettings() { Top = 10, Bottom = 10, Left = 10, Right = 10 }
},
Objects = {
new ObjectSettings() {
HtmlContent = "<html><body><h1>Landscape Document</h1><p>Custom page settings</p></body></html>",
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("landscape.pdf", pdf);
}
}
Imports DinkToPdf
Imports DinkToPdf.Contracts
Imports System.IO
Module Program
Sub Main()
Dim converter = New SynchronizedConverter(New PdfTools())
Dim doc = New HtmlToPdfDocument() With {
.GlobalSettings = New GlobalSettings() With {
.ColorMode = ColorMode.Color,
.Orientation = Orientation.Landscape,
.PaperSize = PaperKind.Letter,
.Margins = New MarginSettings() With {.Top = 10, .Bottom = 10, .Left = 10, .Right = 10}
},
.Objects = {
New ObjectSettings() With {
.HtmlContent = "<html><body><h1>Landscape Document</h1><p>Custom page settings</p></body></html>"
}
}
}
Dim pdf As Byte() = converter.Convert(doc)
File.WriteAllBytes("landscape.pdf", pdf)
End Sub
End Module
IronPDF 方法:
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter;
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
var pdf = renderer.RenderHtmlAsPdf("<html><body><h1>Landscape Document</h1><p>Custom page settings</p></body></html>");
pdf.SaveAs("landscape.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter;
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
var pdf = renderer.RenderHtmlAsPdf("<html><body><h1>Landscape Document</h1><p>Custom page settings</p></body></html>");
pdf.SaveAs("landscape.pdf");
}
}
Imports IronPdf
Imports IronPdf.Rendering
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape
renderer.RenderingOptions.MarginTop = 10
renderer.RenderingOptions.MarginBottom = 10
renderer.RenderingOptions.MarginLeft = 10
renderer.RenderingOptions.MarginRight = 10
Dim pdf = renderer.RenderHtmlAsPdf("<html><body><h1>Landscape Document</h1><p>Custom page settings</p></body></html>")
pdf.SaveAs("landscape.pdf")
End Sub
End Class
Haukcode.DinkToPdf将设置嵌套在MarginSettings对象。 IronPDF提供了直接的PaperOrientation和各个边距属性。
Haukcode.DinkToPdf API 到IronPDF的映射参考
这种映射通过显示直接的 API 对应关系来加速迁移:
转换器类映射
| Haukcode.DinkToPdf | IronPDF |
|---|---|
SynchronizedConverter |
ChromePdfRenderer |
BasicConverter |
ChromePdfRenderer |
PdfTools |
不适用 |
IConverter |
不适用 |
文档配置映射
| Haukcode.DinkToPdf | IronPDF |
|---|---|
HtmlToPdfDocument |
方法调用 |
GlobalSettings |
RenderingOptions |
ObjectSettings |
RenderingOptions |
converter.Convert(doc) |
renderer.RenderHtmlAsPdf(html) |
GlobalSettings 属性映射
| 全局设置属性 | IronPDF 属性 |
|---|---|
ColorMode |
RenderingOptions.GrayScale |
Orientation |
RenderingOptions.PaperOrientation |
PaperSize |
RenderingOptions.PaperSize |
Margins.Top |
RenderingOptions.MarginTop |
Margins.Bottom |
RenderingOptions.MarginBottom |
Margins.Left |
RenderingOptions.MarginLeft |
Margins.Right |
RenderingOptions.MarginRight |
对象设置属性映射
| 对象设置属性 | IronPDF 同等产品 |
|---|---|
HtmlContent |
RenderHtmlAsPdf() 的第一个参数 |
Page (URL) |
renderer.RenderUrlAsPdf(url) |
HeaderSettings.Right = "[page]" |
{page} 在HtmlHeader.HtmlFragment 内 |
占位符语法迁移
| Haukcode.DinkToPdf | IronPDF |
|---|---|
[page] |
{page} |
[toPage] |
{total-pages} |
[date] |
{date} |
常见迁移问题和解决方案
问题 1:单例需求
Haukcode.DinkToPdf: 由于本地wkhtmltopdf二进制文件的线程安全问题,需要将SynchronizedConverter作为单例。
Solution: IronPDF的ChromePdfRenderer设计时就考虑到了线程安全,无需单例:
// Before (DinkToPdf) - MUST be singleton
services.AddSingleton(typeof(IConverter), new SynchronizedConverter(new PdfTools()));
// After (IronPDF) - Can be singleton or transient (both work)
services.AddSingleton<IPdfService, IronPdfService>();
// Or services.AddTransient<IPdfService, IronPdfService>() - both are safe!
// Before (DinkToPdf) - MUST be singleton
services.AddSingleton(typeof(IConverter), new SynchronizedConverter(new PdfTools()));
// After (IronPDF) - Can be singleton or transient (both work)
services.AddSingleton<IPdfService, IronPdfService>();
// Or services.AddTransient<IPdfService, IronPdfService>() - both are safe!
' Before (DinkToPdf) - MUST be singleton
services.AddSingleton(GetType(IConverter), New SynchronizedConverter(New PdfTools()))
' After (IronPDF) - Can be singleton or transient (both work)
services.AddSingleton(Of IPdfService, IronPdfService)()
' Or services.AddTransient(Of IPdfService, IronPdfService)() - both are safe!
问题 2:本地二进制依赖关系
Haukcode.DinkToPdf:需要特定平台的本地库(libwkhtmltox.dll/so/dylib)。
解决方案:IronPDF是独立的,没有本地二进制依赖关系。 迁移后删除这些文件:
libwkhtmltox.dll(Windows)libwkhtmltox.so(Linux)libwkhtmltox.dylib(macOS)
问题 3:返回类型差异
Haukcode.DinkToPdf: converter.Convert() 直接返回byte[]。
Solution: IronPDF返回一个带有多个输出选项的PdfDocument对象:
var pdf = renderer.RenderHtmlAsPdf(html);
byte[] bytes = pdf.BinaryData; // Get bytes
pdf.SaveAs("output.pdf"); // Or save directly
var pdf = renderer.RenderHtmlAsPdf(html);
byte[] bytes = pdf.BinaryData; // Get bytes
pdf.SaveAs("output.pdf"); // Or save directly
Dim pdf = renderer.RenderHtmlAsPdf(html)
Dim bytes As Byte() = pdf.BinaryData ' Get bytes
pdf.SaveAs("output.pdf") ' Or save directly
问题 4:页眉/页脚占位符语法
Haukcode.DinkToPdf: 使用方括号语法例如[toPage]。
解决方案:更新IronPDF的大括号占位符:
// Before (DinkToPdf)
HeaderSettings = { Right = "Page [page] of [toPage]" }
// After (IronPDF)
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
HtmlFragment = "<span style='float:right'>Page {page} of {total-pages}</span>"
};
// Before (DinkToPdf)
HeaderSettings = { Right = "Page [page] of [toPage]" }
// After (IronPDF)
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
HtmlFragment = "<span style='float:right'>Page {page} of {total-pages}</span>"
};
' Before (DinkToPdf)
HeaderSettings = New With {.Right = "Page [page] of [toPage]"}
' After (IronPDF)
renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter With {
.HtmlFragment = "<span style='float:right'>Page {page} of {total-pages}</span>"
}
Haukcode.DinkToPdf 迁移检查表
迁移前任务
审核您的代码库,确定所有 DinkToPdf 的使用情况:
# Find DinkToPdf namespace usage
grep -r "using DinkToPdf\|using Haukcode" --include="*.cs" .
# Find converter usage
grep -r "SynchronizedConverter\|BasicConverter\|HtmlToPdfDocument" --include="*.cs" .
# Find native library loading
grep -r "wkhtmltopdf\|libwkhtmltox" --include="*.cs" --include="*.csproj" .
# Find GlobalSettings/ObjectSettings usage
grep -r "GlobalSettings\|ObjectSettings\|MarginSettings" --include="*.cs" .
# Find DinkToPdf namespace usage
grep -r "using DinkToPdf\|using Haukcode" --include="*.cs" .
# Find converter usage
grep -r "SynchronizedConverter\|BasicConverter\|HtmlToPdfDocument" --include="*.cs" .
# Find native library loading
grep -r "wkhtmltopdf\|libwkhtmltox" --include="*.cs" --include="*.csproj" .
# Find GlobalSettings/ObjectSettings usage
grep -r "GlobalSettings\|ObjectSettings\|MarginSettings" --include="*.cs" .
记录当前的ObjectSettings配置。 确定任何可以删除的本地库加载代码。
代码更新任务
1.删除 DinkToPdf NuGet 软件包
- 安装IronPDF NuGet包
- 将名称空间导入从
IronPdf - 用
SynchronizedConverter - 将
HtmlToPdfDocument模式转换为直接方法调用 - 将
RenderingOptions - 将
RenderingOptions - 更新占位符语法(
[page]→[toPage]→{total-pages}) 9.在启动时添加IronPDF许可证初始化功能
基础架构清理任务
1.删除本地二进制文件 (libwkhtmltox.*) 2.删除本地库加载代码 3.如果存在,移除 CustomAssemblyLoadContext 4.更新依赖注入(不再需要单例) 5.删除本地二进制文件的平台检测代码
迁移后测试
迁移后,验证这些方面:
- 测试 HTML 到 PDF 的转换
- 测试 URL 到 PDF 的转换
- 验证页面设置(大小、方向、页边距)
- 用占位符验证页眉和页脚
- 使用实际的 HTML 模板进行测试
- 负载下的性能测试
迁移到IronPDF的主要优势
从 Haukcode.DinkToPdf 迁移到IronPDF有几个关键优势:
安全性:消除 CVE-2022-35583 (SSRF) 和其他 wkhtmltopdf 漏洞,这些漏洞永远不会被修复。
现代渲染引擎:使用持续更新的 Chromium 内核,而不是 2015 年就已弃用的 Qt WebKit 内核。完全支持 HTML5、CSS3 和 JavaScript。
无本地二进制文件:自包含库,无需管理任何平台特定的 DLL 文件。 简化在 Windows、Linux 和 macOS 上的部署。
Thread Safety: 无需单例要求—可在任何模式中自由使用ChromePdfRenderer,包括每个请求实例化。
Simpler API: 直接方法调用(RenderUrlAsPdf()),而非复杂的文档对象构建。
积极开发:IronPDF的定期发布周期使其与当前.NET版本兼容,包括.NET Framework 4.6.2+、.NET Core 3.1+以及.NET 5/6/7/8/9/10。

