I am running into a memory issue when trying to perform a mail merge. I need to do two things:
1. Generate individual PDF files to be stored on a file share
2. generate a single PDF so it could be sent to a printer as a single job.
I am noticing, that after my large PDF file is generated, the memory usage remains very large. When I re-run the process, it starts climbing up, but then falls back down to an acceptable level during the generation of single document, only to climb back up during the final single PDF. I am pasting my code below. For some odd reason my random data isn't actually making it into the files, but since that's not my problem at this moment, I am not concerned about it.
using
System;
using
System.Collections.Generic;
using
System.Data;
using
System.IO;
using
System.Linq;
using
System.Threading.Tasks;
using
Telerik.WinForms.Documents.FormatProviders.OpenXml.Docx;
using
Telerik.WinForms.Documents.FormatProviders.Pdf;
using
Telerik.WinForms.Documents.Model;
namespace
MailMergeMemoryBenchmark
{
public
partial
class
RadForm1 : Telerik.WinControls.UI.RadForm
{
List<DummyItem> dataSource;
public
RadForm1()
{
//get the rest of the string at http://pastebin.com/i6PZiJ1c
byte
[] template = Convert.FromBase64String(@
"UEsDBBQ...[TRUNCATED]"
);
dataSource =
new
List<DummyItem>();
for
(
int
i = 0; i < 1000; i++)
{
dataSource.Add(DummyItem.GetRandom());
}
InitializeComponent();
var provider =
new
DocxFormatProvider();
radRichTextEditor1.Document = provider.Import(template);
radRichTextEditor1.ScaleFactor =
new
Telerik.WinForms.Documents.Model.SizeF(.4f, .4f);
radRichTextEditor1.ChangeAllFieldsDisplayMode(FieldDisplayMode.Code);
radRichTextEditor1.Document.ShowMergeFieldsHighlight =
true
;
radRichTextEditor1.Document.MailMergeDataSource.ItemsSource = dataSource;
}
private
async
void
btnPerformMailMerge_Click(
object
sender, EventArgs e)
{
btnPerformMailMerge.Enabled =
false
;
var progress =
new
Progress<
string
>(value => UpdateProgress(value));
await Go(progress);
btnPerformMailMerge.Enabled =
true
;
}
private
void
UpdateProgress(
string
value)
{
radLabel1.Text = value + Environment.NewLine;
}
private
Task<
bool
> Go(IProgress<
string
> progress)
{
return
Task.Run(() =>
{
var pdfProvider =
new
PdfFormatProvider();
PdfExportSettings pdfExportSettings =
new
PdfExportSettings()
{
ContentsCompressionMode = PdfContentsCompressionMode.Automatic,
ContentsDeflaterCompressionLevel = 9,
FloatingUIContainersExportMode = PdfInlineUIContainersExportMode.Image,
ImagesCompressionMode = PdfImagesCompressionMode.Automatic,
ImagesDeflaterCompressionLevel = 9,
InlineUIContainersExportMode = PdfInlineUIContainersExportMode.Image,
};
pdfProvider.ExportSettings = pdfExportSettings;
byte
[] letterBytes;
radRichTextEditor1.Document.MailMergeDataSource.MoveToFirst();
int
i = 0;
do
{
using
(var document = radRichTextEditor1.Document.MailMergeCurrentRecord())
{
letterBytes = pdfProvider.Export(document);
File.WriteAllBytes($
"{i}-{DateTime.Now.Ticks}.pdf"
, letterBytes);
}
letterBytes =
null
;
progress.Report($
"Merged {i + 1} out of {dataSource.Count()}"
);
i++;
}
while
(radRichTextEditor1.Document.MailMergeDataSource.MoveToNext());
progress.Report($
"Starting large PDF creation"
);
using
(var document = radRichTextEditor1.MailMerge(
true
))
{
letterBytes = pdfProvider.Export(document);
File.WriteAllBytes($
"ALL RECORDS-{DateTime.Now.Ticks}.pdf"
, letterBytes);
}
progress.Report($
"Done with large PDF creation"
);
letterBytes =
null
;
pdfProvider =
null
;
pdfExportSettings =
null
;
GC.Collect();
return
true
;
});
}
}
internal
class
DummyItem
{
public
string
ContactName;
public
string
CompanyName;
public
string
Address;
public
static
DummyItem GetRandom()
{
return
new
DummyItem()
{
ContactName = RandomStringGenerator.RandomString(20, 40),
CompanyName = RandomStringGenerator.RandomString(20, 40),
Address = RandomStringGenerator.RandomString(100, 200)
};
}
}
internal
static
class
RandomStringGenerator
{
private
const
string
chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 "
;
private
static
Random random =
new
Random();
public
static
string
RandomString(
int
minLength,
int
maxLength)
{
var length = random.Next(minLength, maxLength);
return
new
string
(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
}
}