Cannot access a closed stream in pdf generation
Solution 1
The solution was simple, just putting a .ToList()
to my collection in the foreach
loop:
foreach (TableObject to in myTables.ToList())
{
//some code stuff
This answer under this question helped me to solve this problem.
Solution 2
PdfWriter closes the stream by default. Just add the following line after PdfWriter.GetInstance
writer.CloseStream = false;
Hack4Life
Basically I live on the internet. But sometimes I also live in Austria. I love photography, I programm Apps with Xamarin.IOS and have the most beautiful girlfriend. I'm also the founder and CEO of Hack4Life, photographer/videographer of UnnamedProduction, coder [web/iOS] of Alpscapes(R) and many more sites.
Updated on June 09, 2022Comments
-
Hack4Life about 2 years
I get the following error message when I try to build a PDF file using iTextSharp with multiple tables:
Cannot access a closed Stream.
Here is my code:
//Create a byte array that will eventually hold our final PDF Byte[] bytes; List<TableObject> myTables = getTables(); TableObject currentTable = new TableObject(); //Boilerplate iTextSharp setup here //Create a stream that we can write to, in this case a MemoryStream using (MemoryStream ms = new MemoryStream()) { //Create an iTextSharp Document which is an abstraction of a PDF but **NOT** a PDF using (Document doc = new Document(PageSize.A4, 10f, 10f, 10f, 0f)) { foreach (TableObject to in myTables) { //Create a writer that's bound to our PDF abstraction and our stream using (PdfWriter writer = PdfWriter.GetInstance(doc, ms)) { if (!doc.IsOpen()) { //Open the document for writing doc.Open(); } //Get the data from database corresponding to the current tableobject and fill all the stuff we need! DataTable dt = getDTFromID(to._tableID); Object[] genObjects = new Object[5]; genObjects = gen.generateTable(dt, currentTable._tableName, currentTable._tableID.ToString(), currentTable, true); StringBuilder sb = (StringBuilder)genObjects[1]; String tableName = sb.ToString(); Table myGenTable = (Table)genObjects[0]; String table = genObjects[2].ToString(); using (StringReader srHtml = new StringReader(table)) { //Parse the HTMLiTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, srHtml); } //should give empty page at the end, need to fix it later doc.NewPage(); } } doc.Close(); } //After all of the PDF "stuff" above is done and closed but **before** we //close the MemoryStream, grab all of the active bytes from the stream bytes = ms.ToArray(); } //Now we just need to do something with those bytes. Response.ContentType = "application/pdf"; Response.AppendHeader("Content-Disposition", "attachment; filename=Report_complete.pdf"); Response.BinaryWrite(bytes);
Here is the complete stacktrace from my asp.net application:
[ObjectDisposedException: Cannot access a closed Stream.]
System.IO.__Error.StreamIsClosed() +57
System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count) +11011171 iTextSharp.text.pdf.OutputStreamCounter.Write(Byte[] buffer, Int32 offset, Int32 count) +52
iTextSharp.text.pdf.PdfIndirectObject.WriteTo(Stream os) +53
iTextSharp.text.pdf.PdfBody.Write(PdfIndirectObject indirect, Int32 refNumber, Int32 generation) +100
iTextSharp.text.pdf.PdfBody.Add(PdfObject objecta, Int32 refNumber, Int32 generation, Boolean inObjStm) +385
iTextSharp.text.pdf.PdfWriter.AddToBody(PdfObject objecta, PdfIndirectReference refa) +51
iTextSharp.text.pdf.Type1Font.WriteFont(PdfWriter writer, PdfIndirectReference piref, Object[] parms) +317
iTextSharp.text.pdf.FontDetails.WriteFont(PdfWriter writer) +296
iTextSharp.text.pdf.PdfWriter.AddSharedObjectsToBody() +180
iTextSharp.text.pdf.PdfWriter.Close() +86
iTextSharp.text.DocWriter.Dispose() +10
System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +51 System.Web.UI.Control.OnLoad(EventArgs e) +92
System.Web.UI.Control.LoadRecursive() +54
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +772The
bytes
-Array should be accessable inside the using statements, but it looks like that there is the error.I've tried moving the
foreach
loop inside theusing(writer ...)
block://Create a byte array that will eventually hold our final PDF //must be outside of the foreach loop (and everything else), because we store every single generated table in here for the final pdf!! Byte[] bytes; List<TableObject> myTables = getTables(); TableObject currentTable = new TableObject(); //Boilerplate iTextSharp setup here //Create a stream that we can write to, in this case a MemoryStream using (MemoryStream ms = new MemoryStream()) { //Create an iTextSharp Document which is an abstraction of a PDF but **NOT** a PDF using (Document doc = new Document(PageSize.A4, 10f, 10f, 10f, 0f)) { //Create a writer that's bound to our PDF abstraction and our stream using (PdfWriter writer = PdfWriter.GetInstance(doc, ms)) { //loop all tableobjects inside the document & the instance of PDFWriter itself! foreach (TableObject to in myTables) { //only happens on the first run! if (!doc.IsOpen()) { //Open the document for writing doc.Open(); } //Get the data from database corresponding to the current tableobject and fill all the stuff we need! DataTable dt = getDTFromID(to._tableID); Object[] genObjects = new Object[5]; genObjects = gen.generateTable(dt, currentTable._tableName, currentTable._tableID.ToString(), currentTable, true); StringBuilder sb = (StringBuilder)genObjects[1]; String tableName = sb.ToString(); Table myGenTable = (Table)genObjects[0]; String table = genObjects[2].ToString(); using (StringReader srHtml = new StringReader(table)) { //Parse the HTML iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, srHtml); } //this will probably render a whole new page at the end of the file!! need to be fixed later!!! doc.NewPage(); } //After all of the PDF "stuff" above is done and closed but **before** we //close the MemoryStream, grab all of the active bytes from the stream bytes = ms.ToArray(); } doc.Close(); } } //Now we just need to do something with those bytes. Response.ContentType = "application/pdf"; Response.AppendHeader("Content-Disposition", "attachment; filename=ShiftReport_complete.pdf"); Response.BinaryWrite(bytes);
But I still get the same error.