It's confusing but read the docs for MemoryStream.ToArray
. This method can be called after the stream is closed because, while MemoryStream
does implement IDisposable
since it is a Stream
, the method doesn't actually do anything other than set a flag.
The issue is that when Document
is disposed it automatically disposes the stream you passed to it. That is the RAII pattern that you might have heard of. Since you gave a lifetime-managed object to Document
it is responsible for cleaning it up. You actually don't need your Using
on the stream at all. But that also means you need to ensure the Document
stays around until you are done with the stream.
Here's the updated version of your code.
Public Shared Sub MergePDFs(ByVal files As List(Of String), ByVal filename As String)
Using mem As New MemoryStream()
Dim readers As New List(Of PdfReader)
Using doc As New Document
Dim copy As New PdfCopy(doc, mem)
copy.SetMergeFields()
doc.Open()
For Each strfile As String In files
Dim reader As New PdfReader(strfile)
copy.AddDocument(reader)
readers.Add(reader)
Next
If filename = "finalbillfiles.pdf" Then
filename = "E:/" & filename
Using file As New FileStream(filename, FileMode.Create, FileAccess.Write)
mem.WriteTo(file)
End Using
End If
End Using
For Each reader As PdfReader In readers
reader.Close()
Next
HttpContext.Current.Response.Clear()
HttpContext.Current.Response.ContentType = "application/pdf"
HttpContext.Current.Response.AppendHeader("Content-Disposition", "inline; filename=" + filename)
HttpContext.Current.Response.BinaryWrite(mem.ToArray)
HttpContext.Current.Response.OutputStream.Flush()
End Using
End Sub
Basically ensure Document
persists until you're done with the stream (except ToArray
) and because iTextSharp doesn't really manage resources well you also need to keep the PdfReader
instances open until after the document is closed.