Why does breaking out of a foreach loop cause comp

2019-08-25 04:01发布

问题:

Based on the suggestion in the comments here, I refactored my method to try to assign data to a MemoryStream outside of the iTextSharp.text.Document "using" (but within the MemoryStream using clause):

internal static HttpResponseMessage GeneratePDFOfReportFutures()
{
    HttpResponseMessage result = null;
    futureReports = GetAllFutureReports();
    try
    {
        using (var ms = new MemoryStream())
        {
            using (var doc = new Document(PageSize.A4.Rotate(), 25, 25, 25, 25)) // the "Rotate" makes it landscape orientation
            {
                using (PdfWriter.GetInstance(doc, ms))
                {
                    doc.Open();
                    . . .
                    // "int i" is for testing a quick exit of this long-running loop
                    int i = 0;
                    foreach (QueuedReports qr in futureReports)
                    {
                        var tblRow = new PdfPTable(6)
                        {
                            WidthPercentage = 80,
                            SpacingBefore = 4f
                        };
                        float[] tblRowWidths = new float[] { 220f, 180f, 220f, 160f, 160f, 340f };
                        tblRow.SetWidths(tblRowWidths);
                        tblRow.HorizontalAlignment = Element.ALIGN_LEFT;

                        var phraseRptName = new Phrase(qr.ReportName, helvetica9);
                        var cellRptName = GetCellForBorderedTable(phraseRptName, Element.ALIGN_CENTER, BaseColor.WHITE);
                        cellRptName.VerticalAlignment = Element.ALIGN_MIDDLE;
                        tblRow.AddCell(cellRptName);

                        . . .
                        tblRow.AddCell(cellRecipients);

                        doc.Add(tblRow);

                        i++;
                        if (i >= 12)
                        {
                            break;
                        }
                    } // foreach
                } // pdfWriter
            } // doc
            var bytes = ms.ToArray();
            result = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new ByteArrayContent(bytes)
            };
            result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = string.Format("{0}.pdf", "test")
            };
            result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        } // memoryStream               
    } // try
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    return result;
} // GeneratePDFOfReportFutures

With a breakpoint in the "break" line, I step (F10) and the following exception is caught prior to reaching the assignment to bytes:

System.ObjectDisposedException was caught HResult=-2146232798
Message=Cannot access a closed Stream. Source=mscorlib
ObjectName="" StackTrace: at System.IO.__Error.StreamIsClosed() at System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count) at iTextSharp.text.pdf.OutputStreamCounter.Write(Byte[] buffer, Int32 offset, Int32 count) at iTextSharp.text.pdf.PdfIndirectObject.WriteTo(Stream os) at iTextSharp.text.pdf.PdfWriter.PdfBody.Write(PdfIndirectObject indirect, Int32 refNumber, Int32 generation) at iTextSharp.text.pdf.PdfWriter.PdfBody.Add(PdfObject objecta, Int32 refNumber, Int32 generation, Boolean inObjStm) at iTextSharp.text.pdf.PdfWriter.PdfBody.Add(PdfObject objecta, PdfIndirectReference refa, Boolean inObjStm) at iTextSharp.text.pdf.PdfWriter.PdfBody.Add(PdfObject objecta, PdfIndirectReference refa) at iTextSharp.text.pdf.PdfWriter.AddToBody(PdfObject objecta, PdfIndirectReference refa) at iTextSharp.text.pdf.Type1Font.WriteFont(PdfWriter writer, PdfIndirectReference piref, Object[] parms) at iTextSharp.text.pdf.FontDetails.WriteFont(PdfWriter writer) at iTextSharp.text.pdf.PdfWriter.AddSharedObjectsToBody() at iTextSharp.text.pdf.PdfWriter.Close() at iTextSharp.text.DocWriter.Dispose()

Since accessing of PdfWriter and/or Doc appeared to be causing the problem, it would seem I need to move the writing code inside not only the doc using, but also the pdfWriter using, so I did that, moving the code like so:

                . . .
                } // foreach
                var bytes = ms.ToArray();
                result = new HttpResponseMessage(HttpStatusCode.OK)
                {
                    Content = new ByteArrayContent(bytes)
                };
                result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
                {
                    FileName = string.Format("{0}.pdf", "test")
                };
                result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            } // pdfWriter
        } // doc
    } // memoryStream               
} // try
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}
return result;

...but I still get precisely the same exception. However, there is a difference between what I'm seeing now and what's described in the last post in that the exception is not thrown until I F10 on this line:

} // pdfWriter

If I move the return line above (and still keep it below the catch block) like so:

    return result;
} // pdfWriter

...the exception is thrown on F10ing on the "return result" line.

Why is this failing, and how can I prevent it?