.NET Core 6 MVC用iTextSharp实现DataTable转PDF加自定义页眉页脚报错
问题:.NET Core 6 MVC中iTextSharp添加页眉页脚后PDF生成卡顿崩溃
需求与现状
- 需求:在.NET Core 6 MVC环境下,使用iTextSharp 5.5.13.3将DataTable中的数据生成PDF,并添加包含公司Logo的自定义页眉和包含公司地址的自定义页脚。
- 现状:注释页眉页脚事件处理器代码时,可正常生成含DataTable数据的PDF;启用事件处理器后,代码执行到
document.Add(table)处时卡顿,最终导致Visual Studio停止运行。
问题原因
在iTextSharp的PdfPageEventHelper的OnStartPage/OnEndPage方法中直接调用document.Add()会触发无限循环:添加页眉/页脚的操作会重新触发页面事件,导致OnStartPage/OnEndPage被反复调用,最终引发死循环和程序崩溃。
修复方案
1. 调整核心处理方法(增加页面边距)
在创建Document实例时,预留足够的页眉页脚空间,避免内容被覆盖:
private void ProcessEMICalendarDocument(DocumentGenerationRequestModel item, List<MemoryStream> templateStreams, string userCode) { var dataTable = dao.GetDataforEMICalendar(item.LoanAccountNo, connectionString); if (dataTable != null && dataTable.Rows.Count > 0) { using (MemoryStream memoryStream = new MemoryStream()) { // 预留页眉页脚空间:左、右、上、下边距(单位:磅) using (Document document = new Document(PageSize.A4, 36, 36, 72, 54)) { PdfWriter writer = PdfWriter.GetInstance(document, memoryStream); HeaderFooter eventHelper = new HeaderFooter(); // 传入Logo路径(根据实际项目路径调整) eventHelper.LogoPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images", "company-logo.png"); writer.PageEvent = eventHelper; document.Open(); PdfPTable table = CreatePdfPTable(dataTable, 10); if (table.Rows.Count > 0) { document.Add(table); document.Close(); MemoryStream clonedMemoryStream = new MemoryStream(memoryStream.ToArray()); clonedMemoryStream.Position = 0; templateStreams.Add(clonedMemoryStream); } else { Console.WriteLine("The PdfPTable has no rows."); } } } } else { Console.WriteLine("The DataTable is null or empty."); } }
2. 修复页眉页脚事件处理器类
使用PdfWriter.DirectContent直接绘制页眉页脚,避免触发循环:
public class HeaderFooter : PdfPageEventHelper { private bool addHeader = true; private bool addFooter = true; // 用于存储Logo路径 public string LogoPath { get; set; } public override void OnStartPage(PdfWriter writer, Document document) { if (!addHeader) return; PdfContentByte cb = writer.DirectContent; // 设置页眉位置(距离页面顶部20磅) float headerY = document.PageSize.Top - 20; // 添加Logo if (!string.IsNullOrEmpty(LogoPath) && File.Exists(LogoPath)) { Image logo = Image.GetInstance(LogoPath); // 调整Logo大小和位置 logo.ScaleToFit(80, 40); logo.SetAbsolutePosition(document.LeftMargin, headerY - logo.ScaledHeight); cb.AddImage(logo); } // 添加页眉文字(右侧对齐) Phrase headerText = new Phrase("公司名称", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD)); ColumnText.ShowTextAligned(cb, Element.ALIGN_RIGHT, headerText, document.PageSize.Right - document.RightMargin, headerY, 0); } public override void OnEndPage(PdfWriter writer, Document document) { if (!addFooter) return; PdfContentByte cb = writer.DirectContent; // 设置页脚位置(距离页面底部20磅) float footerY = document.Bottom + 20; // 添加页脚地址文字(居中对齐) Phrase footerText = new Phrase("公司地址:XX市XX区XX路XX号 | 联系电话:XXX-XXXXXXX", new Font(Font.FontFamily.HELVETICA, 10, Font.NORMAL)); ColumnText.ShowTextAligned(cb, Element.ALIGN_CENTER, footerText, document.PageSize.Width / 2, footerY, 0); // 添加页码(右侧对齐) Phrase pageNumber = new Phrase($"第 {writer.PageNumber} 页", new Font(Font.FontFamily.HELVETICA, 10, Font.NORMAL)); ColumnText.ShowTextAligned(cb, Element.ALIGN_RIGHT, pageNumber, document.PageSize.Right - document.RightMargin, footerY, 0); } }
关键注意事项
- 禁止在
OnStartPage/OnEndPage中调用document.Add(),必须通过PdfContentByte直接操作内容 - 必须预留足够的页面边距,确保页眉页脚不会覆盖正文内容
- Logo路径要根据实际项目结构调整,确保程序能读取到图片文件
内容的提问来源于stack exchange,提问作者Ram Anugandula
相关产品推荐
相关产品推荐

