The following code is used to stitch together existing PDFs [As an aside we are using TallComponents to do the actual stitching, in case you were wondering what PDFUtility
is]:
PDFUtility.Document docFinal = new PDFUtility.Document();
PDFUtility.Document docToAdd = null;
byte[] combinedFile;
foreach (byte[] content in fileContents)
{
MemoryStream fileContentStream = new MemoryStream(content);
docToAdd = new PDFUtility.Document(fileContentStream);
docFinal.Pages.AddRange(docToAdd.Pages.CloneToArray());
}
using (MemoryStream stream = new MemoryStream())
{
docFinal.Write(stream);
combinedFile = stream.ToArray();
}
The glaring problem with this code is this command:
MemoryStream fileContentStream = new MemoryStream(content);
The memory stream fileContentStream
is not getting disposed, potentially (I believe) holding onto resoures longer than needed.
The obvious solution would be to wrap the creation of the MemoryStream in a using
block. The code would then look like this:
PDFUtility.Document docFinal = new PDFUtility.Document();
PDFUtility.Document docToAdd = null;
byte[] combinedFile;
foreach (byte[] content in fileContents)
{
using (MemoryStream stream = new MemoryStream())
{
MemoryStream fileContentStream = new MemoryStream(content);
docToAdd = new PDFUtility.Document(fileContentStream);
docFinal.Pages.AddRange(docToAdd.Pages.CloneToArray());
}
}
using (MemoryStream stream = new MemoryStream())
{
docFinal.Write(stream);
combinedFile = stream.ToArray();
}
The use of the using block in the above code causes the code to fail on this line (because the streams were previously disposed):
docFinal.Write(stream);
One possible solution would be to keep track of all the MemoryStream instances and dispose of them after they are done being used. This is the code for that:
PDFUtility.Document docFinal = new PDFUtility.Document();
PDFUtility.Document docToAdd = byte[] combinedFile;
List<MemoryStream> streams = new List<MemoryStream>();
foreach (byte[] content in fileContents)
{
MemoryStream fileContentStream = new MemoryStream(content);
streams.Add(fileContentStream); //EACH INSTANCE OF A STREAM IS TRACKED
docToAdd = new PDFUtility.Document(fileContentStream);
docFinal.Pages.AddRange(docToAdd.Pages.CloneToArray());
}
using (MemoryStream stream = new MemoryStream())
{
docFinal.Write(stream);
combinedFile = stream.ToArray();
}
streams.ForEach(s => s.Dispose()); //DISPOSE OF ALL STREAMS HERE
The code above works. I am simply delaying the Dispose until after the the final document is written out.
However, this doesn't seem like the "best" solution. Is there any way to implement using blocks (and thus guaranteeing the objects are properly disposed?
docFInal.Flush
method you can call before exiting the loop?