views:

2745

answers:

5

I've asked a couple of questions here but am still having issues. I'd appreciate if you could tell me what I am doing wrong in my code. I run the code above from a ASP.Net page and get "Cannot Access a Closed Stream".

var doc = new Document();

MemoryStream memoryStream = new MemoryStream();

PdfWriter.GetInstance(doc, memoryStream);
doc.Open();
doc.Add(new Paragraph("First Paragraph"));
doc.Add(new Paragraph("Second Paragraph"));

doc.Close(); //if I remove this line the email attachment is sent but with 0 bytes 

MailMessage mm = new MailMessage("[email protected]", "[email protected]")
{
    Subject = "subject",
    IsBodyHtml = true,
    Body = "body"
};

mm.Attachments.Add(new Attachment(memoryStream, "test.pdf"));
SmtpClient smtp = new SmtpClient
{
    Host = "smtp.gmail.com",
    Port = 587,
    EnableSsl = true,
    Credentials = new NetworkCredential("[email protected]", "my_password")
};

smtp.Send(mm); //the "Cannot Access a Closed Stream" error is thrown here

Thanks!!!

EDIT:

Just to help somebody looking for the answer to this question, the code to send a pdf file attached to an email without having to physically create the file is below (thanks to Ichiban and Brianng):

var doc = new Document();
MemoryStream memoryStream = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(doc, memoryStream);

doc.Open();
doc.Add(new Paragraph("First Paragraph"));
doc.Add(new Paragraph("Second Paragraph"));

writer.CloseStream = false;
doc.Close();
memoryStream.Position = 0;

MailMessage mm = new MailMessage("[email protected]", "[email protected]")
{
    Subject = "subject",
    IsBodyHtml = true,
    Body = "body"
};

mm.Attachments.Add(new Attachment(memoryStream, "filename.pdf"));
SmtpClient smtp = new SmtpClient
{
    Host = "smtp.gmail.com",
    Port = 587,
    EnableSsl = true,
    Credentials = new NetworkCredential("[email protected]", "password")

};

smtp.Send(mm);
+1  A: 

Probably calling doc.Close() Disposes the underlying stream. Try removing doc.Close() and instead of that line set memoryStream.Position = 0;

Alternatively you can use a temp file:

var tempFilePath = Path.GetTempFileName();

try 
{           
    var doc = new Document();

    PdfWriter.GetInstance(doc, File.OpenWrite(tempFilePath));
    doc.Open();
    doc.Add(new Paragraph("First Paragraph"));
    doc.Add(new Paragraph("Second Paragraph"));

    doc.Close();

    MailMessage mm = new MailMessage("[email protected]", "[email protected]")
    {
        Subject = "subject",
        IsBodyHtml = true,
        Body = "body"
    };

    mm.Attachments.Add(new Attachment(tempFilePath, "test.pdf"));
    SmtpClient smtp = new SmtpClient
    {
        Host = "smtp.gmail.com",
        Port = 587,
        EnableSsl = true,
        Credentials = new NetworkCredential("[email protected]", "my_password")
    };

    smtp.Send(mm);
}
finally
{
    File.Delete(tempFilePath);
}
huseyint
huseyint, I did what you suggested and the pdf file is sent, but it is only 15 bytes long. When I try opening it, it is corrupted.I feel I am almost there with your suggestion. Any other ideas? Thanks!
Gustavo Cavalcanti
Then try memoryStream.Flush(); before setting the Position
huseyint
Same thing. The file is sent almost empty and corrupted. :(
Gustavo Cavalcanti
Did you give "Creating a temp file" a try?
huseyint
I am working on it right now and let you know shortly. Thanks!
Gustavo Cavalcanti
Huseyint, thanks for your answer. I am pretty sure it would work but Brianng's answer is simpler as it doesn't require dealing with the server's file system. Thanks a lot though!
Gustavo Cavalcanti
Yes, definitely brianng's answer is the right way to achieve this. Glad you solved it!
huseyint
+1  A: 

Can you flush the document or memory stream and then close it after you attach it?

James Conigliaro
Hi James. I did this and the result did not change - I still get the "Cannot Access a Closed Stream" error. :( Other ideas?
Gustavo Cavalcanti
+8  A: 

Have you tried:

PdfWriter writer = PdfWriter.GetInstance(doc, memoryStream);

// Build pdf code...

writer.CloseStream = false;
doc.Close();

// Build email

memoryStream.Position = 0;
mm.Attachments.Add(new Attachment(memoryStream, "test.pdf"));

If my memory serves me correctly, this solved a similar problem in a previous project.

See http://forums.asp.net/t/1093198.aspx

brianng
The set_CloseStream method is only available in the Java version. This is iTextSharp (.NET)
ichiban
Sorry, again I haven't used iTextSharp (.NET) in a while, though the version I used definitely had set_CloseStream.
brianng
Changed to writer.CloseStream, and included related link.
brianng
Brianng, I really appreciate your help. I realize you and Ichiban kind of held my hand through it. Thanks!
Gustavo Cavalcanti
No problem, glad you got it working!
brianng
+2  A: 

I tried the code posted by brianng and it worked. Just change the top of the code to this:

var doc = new Document();
MemoryStream memoryStream = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(doc, memoryStream); //capture the object
doc.Open();
doc.Add(new Paragraph("First Paragraph"));
doc.Add(new Paragraph("Second Paragraph"));
writer.CloseStream = false; //set the closestream property
doc.close(); //close the document without closing the underlying stream
memoryStream.Position = 0;

/* remainder of your code stays the same*/
ichiban
Thanks for taking the time to verify!
brianng
Hi Ichiban,It compiles and it actually sends the email with the attachment, but the attached pdf document come across with 0kb. Did you actually open the pdf an email sent?
Gustavo Cavalcanti
@Gustavo, the file opens correctly in Acrobat viewer. It is about 900 Bytes. Make sure you keep the line: memoryStream.Position=0; right after doc.Close(). I forgot to mention that. (see update above)
ichiban
YES! Thank you so much guys. It finally worked. Since Ichiban's answer was based on brianng's, I think it's fair to mark brianng's answer as correct.
Gustavo Cavalcanti
A: 

I had the same problem and I used this post to solve it.In the code written by brianng

PdfWriter writer = PdfWriter.GetInstance(doc, memoryStream);

// Build pdf code...

writer.CloseStream = false;
doc.Close();

// Build email

memoryStream.Position = 0;
mm.Attachments.Add(new Attachment(memoryStream, "test.pdf"));

I think instead of writing

writer.CloseStream = false and memoryStream.Position = 0;

Just create a new Stream

MemoryStream m = new MemoryStream(memoryStream);

and then call

mm.Attachments.Add(new Attachment(memoryStream, "test.pdf"));

Both work but I think it is better to create the new stream

Zein Sleiman