在 MVC 中使用 itext7 合并 Crystal 报告从流中生成未合并的 pdf

Merging Crystal Reports with itext7 in MVC produces unmerged pdf from stream

我正在尝试在 ASP.net MVC 项目中合并两个(或更多)Crystal 报告,为此我下载了 itext7 NuGet 包。我正在尝试整理一个简单的概念验证,其中我使用一种方法将 pdf 与自身连接起来:

var rpt1 = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
var rpt2 = new CrystalDecisions.CrystalReports.Engine.ReportDocument();

rpt1.Load(Server.MapPath("~/Reports/MyReport.rpt");
rpt2.Load(Server.MapPath("~/Reports/MyReport.rpt");

DataTable table = GetDataMethod();
rpt1.SetDataSource(table);
rpt2.SetDataSource(table);

Stream stream = rpt.ExportToStream(ExportFormatType.PortableDocFormat);
var write = new PdfWriter(stream);
var doc = new PdfDocument(write);
var merger = new PdfMerger(doc);

var doc1 = new PdfDocument(new PdfReader(rpt1.ExportToStream(ExportFormatType.PortableDocFormat)));
var doc2 = new PdfDocument(new PdfReader(rpt2.ExportToStream(ExportFormatType.PortableDocFormat)));

merger.Merge(doc1, 1, doc1.GetNumberOfPages());
merger.Merge(doc2, 1, doc2.GetNumberOfPages());
doc.CopyPagesTo(1, doc2.GetNumberOfPages(), doc2);

stream.Flush();
stream.Position = 0;
return this.File(stream, "application/pdf", "DownloadName.pdf");

你可以看到我有点把所有东西都扔到墙上,看看有什么东西在我同时使用 PdfMerger.Merger()PdfDocument.CopyPagesTo() 的范围内,我认为其中任何一个都应该足够了自己完成工作? (而且,当然,我 运行 代码单独或一起尝试每个代码。)但是当我 运行 上面的代码时,下载的 PDF 未合并,即报告只出现一次. (如果我 运行 它有两个不同的报告,那么只会出现第一个报告。)

现在,我正在 return 播放流,同时我正在使用 PdfMergerPdfDocument 对象做所有有趣的事情,所以对我来说有意义的是流将保持不变。但是我发现 return 流或字节数组(例如 )的所有使用 iText 7 的示例,所以这似乎是它应该工作的方式。

我对代码所做的任何更改要么无效、抛出错误,要么导致浏览器无法读取下载的文件(即无法识别为 PDF)。例如,我尝试将流转换为字节数组并 returning 那个:

using (var ms = new MemoryStream()) {
     stream.CopyTo(ms);
     byte[] bytes = ms.ToArray();
     return new FileContentResult(bytes, "application/pdf");
}

但是当时浏览器打不开下载。当我尝试在 returning 流之前关闭 PdfDocument 时发生了同样的事情(试图强制它将合并写入流)。

您的代码中存在很多与流混淆的地方。通常,流用于输入或输出。 MemoryStream 两者都可以使用,但您需要确保不要关闭它以便能够重新使用它。使用底层字节创建新实例通常比重用现有字节更简单、更清晰,尤其是考虑到它不会对性能产生太大影响,因为底层重数组结构无论如何都会被新实例重用。这是您如何区分流的示例。 ExportToStream returns 你可以从中获取包含 PDF 文件字节的字节数组的流,然后将这些文档加载到 iText 中,同时创建第三个文档,你将合并这两个源文件成。然后你必须确保调用 PdfDocument#Close() 告诉 iText 完成你的文档,然后你可以获取合并文档的结果字节并传递它们,必要时将它们包装成流

var rpt1 = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
var rpt2 = new CrystalDecisions.CrystalReports.Engine.ReportDocument();

rpt1.Load(Server.MapPath("~/Reports/MyReport.rpt");
rpt2.Load(Server.MapPath("~/Reports/MyReport.rpt");

DataTable table = GetDataMethod();
rpt1.SetDataSource(table);
rpt2.SetDataSource(table);

var report1Stream = (MemoryStream)rpt1.ExportToStream(ExportFormatType.PortableDocFormat);
var report2Stream = (MemoryStream)rpt2.ExportToStream(ExportFormatType.PortableDocFormat);

var doc1 = new PdfDocument(new PdfReader(new MemoryStream(report1Stream.ToArray())));
var doc2 = new PdfDocument(new PdfReader(new MemoryStream(report2Stream.ToArray())));

var outStream = new MemoryStream();
var write = new PdfWriter(outStream);
var doc = new PdfDocument(write);
var merger = new PdfMerger(doc);

merger.Merge(doc1, 1, doc1.GetNumberOfPages());
merger.Merge(doc2, 1, doc2.GetNumberOfPages());

doc.Close();
doc1.Close();
doc2.Close();

return this.File(new MemoryStream(outStream.ToArray()), "application/pdf", "DownloadName.pdf");