在C#项目开发中,经常会遇到需要生成PDF格式报表的需求,比如订单详情、数据统计报表、合同文档等。直接操作PDF的底层接口开发成本较高,而基于HTML模板生成PDF的方式,只需要编写熟悉的HTML和CSS代码就能控制报表样式,开发效率会提升很多。DinkToPdf是一个基于WebKit引擎的C# PDF生成库,能够将HTML字符串或者HTML文件转换为PDF,支持自定义页面大小、边距、页眉页脚等配置,非常适合用来实现PDF报表的导出功能。

DinkToPdf环境准备
首先需要在项目中安装DinkToPdf的依赖,它有两个核心的NuGet包,分别是DinkToPdf和DinkToPdf.Native.win-x64,如果是其他系统平台,可以安装对应的Native包。安装完成后,还需要准备一个HTML模板,用来定义PDF报表的样式和内容结构。
安装依赖
在Visual Studio的NuGet包管理器中搜索并安装以下两个包:
- DinkToPdf
- DinkToPdf.Native.win-x64
如果是.NET Core或者.NET 5及以上版本的项目,安装完成后就可以直接使用相关接口。
HTML模板编写
HTML模板就是普通的HTML文件,支持内联CSS样式,下面是一个简单的报表模板示例,包含标题、表格和基本样式:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
font-family: "Microsoft YaHei", sans-serif;
margin: 20px;
}
.report-title {
text-align: center;
font-size: 24px;
font-weight: bold;
margin-bottom: 20px;
}
.report-table {
width: 100%;
border-collapse: collapse;
margin-top: 15px;
}
.report-table th, .report-table td {
border: 1px solid #333;
padding: 8px;
text-align: center;
}
.report-table th {
background-color: #f5f5f5;
}
</style>
</head>
<body>
<div class="report-title">月度销售报表</div>
<div>统计周期:2024年1月1日 - 2024年1月31日</div>
<table class="report-table">
<thead>
<tr>
<th>商品名称</th>
<th>销售数量</th>
<th>销售金额</th>
</tr>
</thead>
<tbody>
<tr>
<td>笔记本电脑</td>
<td>120</td>
<td>960000</td>
</tr>
<tr>
<td>无线鼠标</td>
<td>350</td>
<td>17500</td>
</tr>
</tbody>
</table>
</body>
</html>
核心转换代码实现
DinkToPdf的核心类是HtmlToPdfConverter,需要先初始化转换器实例,然后配置转换参数,最后传入HTML内容生成PDF字节流,再将字节流保存为文件即可。
初始化转换器
首先需要在项目中创建转换器实例,注意DinkToPdf的转换器需要加载对应的Native库,初始化代码如下:
using DinkToPdf;
using DinkToPdf.Contracts;
using System.IO;
public class PdfReportGenerator
{
private readonly IConverter _converter;
public PdfReportGenerator()
{
// 初始化转换器,加载Native库
var context = new CustomAssemblyLoadContext();
context.LoadUnmanagedLibrary(Path.Combine(Directory.GetCurrentDirectory(), "libwkhtmltox.dll"));
_converter = new SynchronizedConverter(new PdfTools());
}
}
如果是.NET Core项目,还需要添加CustomAssemblyLoadContext类来处理Native库的加载,代码如下:
using System.Runtime.Loader;
public class CustomAssemblyLoadContext : AssemblyLoadContext
{
public IntPtr LoadUnmanagedLibrary(string absolutePath)
{
return LoadUnmanagedDll(absolutePath);
}
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
{
return LoadUnmanagedDllFromPath(unmanagedDllName);
}
}
生成PDF报表
接下来编写生成PDF的核心方法,支持传入HTML字符串或者HTML文件路径,生成对应的PDF文件:
public void GeneratePdfFromHtml(string htmlContent, string outputPath)
{
// 配置PDF全局设置
var globalSettings = new GlobalSettings
{
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4,
Margins = new MarginSettings { Top = 10, Bottom = 10, Left = 10, Right = 10 },
DocumentTitle = "PDF报表"
};
// 配置对象设置,这里使用HTML字符串作为内容
var objectSettings = new ObjectSettings
{
PagesCount = true,
HtmlContent = htmlContent,
WebSettings = { DefaultEncoding = "utf-8" },
// 如果需要加载本地HTML文件,可以使用以下配置
// Page = Path.Combine(Directory.GetCurrentDirectory(), "template.html"),
// WebSettings = { LoadImages = true, EnableJavascript = false }
};
// 创建PDF文档配置
var pdf = new HtmlToPdfDocument()
{
GlobalSettings = globalSettings,
Objects = { objectSettings }
};
// 转换生成PDF字节流
byte[] pdfBytes = _converter.Convert(pdf);
// 保存为PDF文件
File.WriteAllBytes(outputPath, pdfBytes);
}
调用示例
在实际使用中,只需要读取HTML模板内容,替换其中的动态数据,然后调用生成方法即可:
class Program
{
static void Main(string[] args)
{
// 读取HTML模板内容
string htmlTemplate = File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), "template.html"));
// 这里可以替换模板中的动态占位符,比如用实际数据替换统计周期、表格内容等
string finalHtml = htmlTemplate.Replace("2024年1月1日 - 2024年1月31日", "2024年2月1日 - 2024年2月29日");
// 生成PDF
var generator = new PdfReportGenerator();
generator.GeneratePdfFromHtml(finalHtml, "销售报表.pdf");
Console.WriteLine("PDF报表生成成功");
}
}
常见问题处理
- 中文显示乱码:确保HTML模板中设置了支持中文的字体,比如
font-family: "Microsoft YaHei", sans-serif,同时HTML的字符编码设置为utf-8。 - 图片无法加载:如果是本地图片,需要使用绝对路径,或者在WebSettings中设置
LoadImages = true,如果是网络图片,确保地址可以正常访问。 - 页面尺寸不符合要求:可以在GlobalSettings中修改
PaperSize属性,支持A3、A4、A5等常见尺寸,也可以自定义宽度和高度。
总结
使用DinkToPdf实现C#生成PDF报表的方式,不需要掌握复杂的PDF底层操作,只需要熟悉HTML和CSS就能快速开发出样式丰富的报表。整个流程分为环境准备、模板编写、代码实现三个步骤,开发效率高,扩展性强,能够满足大部分项目中的PDF导出需求。如果后续需要更复杂的报表样式,只需要修改HTML模板即可,不需要调整核心转换代码。