У меня проблема с iText7 и. NET Core 3.
В моей базе данных есть куча PDF-файлов, и случай использования заключается в том, что каждые несколько дней кто-то должен получать эти файлы как один большой PDF-файл. Проблема в том, что когда ядро asp. net выделяет память для этого файла PDF (~ 50 МБ), оно не освобождает ее. Насколько я знаю, он расположен на куче больших объектов, которые не GCed. Проблема в том, что приложение начинает генерировать исключения OutOfMemory. Итак, я прошу руководство от c# byte [] guru =) Я написал свой код так:
public virtual async Task<ResultEntity> CreateDocument(CancellationToken ct, List<DocEntity> entities)
{
var result = new ResultEntity();
var resultBytes = await base.CreateDocumentA4(async (pdfDoc, doc, ms) =>
{
var merger = new PdfMerger(pdfDoc);
foreach (var entity in entities)
{
PrintEntity print = null;
// removed for readability
if (print != null)
{
MergePdfDocument(merger, print.Bytes );
}
Current++;
await UpdateProgress();
}
}, ct);
result.Bytes = resultBytes;
return result;
}
Базовая реализация выглядит следующим образом:
private async Task<byte[]> CreateDocument(Func<PdfDocument, Document, PdfWriter, Task> operation,
PageSize pageSize, CancellationToken ct)
{
var wProps = new WriterProperties();
wProps.SetPdfVersion(PdfVersion.PDF_2_0);
wProps.SetFullCompressionMode(true);
using (var ms = new MemoryStream())
using (var w = new PdfWriter(ms, wProps))
using (var pdfDoc = new PdfDocument(w))
{
pdfDoc.SetDefaultPageSize(pageSize);
AddDocMeta(pdfDoc);
ct.ThrowIfCancellationRequested();
using (var doc = new Document(pdfDoc, pageSize))
{
await operation(pdfDoc, doc, w);
doc.Close();
}
pdfDoc.Close();
return ms.ToArray();
}
}
public static void MergePdfDocument(PdfMerger merger, byte[] documentSource)
{
var iRandomSrc = new RandomAccessSourceFactory().CreateSource(documentSource);
using (var reader = new PdfReader(iRandomSrc, new ReaderProperties()))
using (var src = new PdfDocument(reader))
{
merger.Merge(src, 1, src.GetNumberOfPages());
src.Close();
}
}
И в. net ядро Я использую пользовательский OutputFormatter, например, так:
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context)
{
var docEntity = (DocumentEntity) context.Object;
if (docEntity.DocumentBytes == null)
{
docEntity.DocumentBytes = Array.Empty<byte>();
}
var response = context.HttpContext.Response;
var contentDisposition = new ContentDispositionHeaderValue("attachment");
if (!string.IsNullOrWhiteSpace(docEntity.Format))
{
switch (docEntity.Format.ToLower())
{
case "pdf":
case "xls":
contentDisposition.SetHttpFileName(docEntity.FileName.ToLower() + "." +
docEntity.Format.ToLower());
break;
}
}
response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();
response.ContentLength = docEntity.DocumentBytes.LongLength;
using (docEntity)
{
await response.Body.WriteAsync(docEntity.DocumentBytes, 0, docEntity.DocumentBytes.Length);
}
}
Так, что я делаю не так? Как мне освободить те надоедливые байты, которые были выделены? Заранее спасибо.