iTextSharp-通过电子邮件附件发送内存中的pdf


100

我在这里问了几个问题,但仍然有问题。如果您能告诉我我在代码中做错了什么,我将不胜感激。我从ASP.Net页运行上面的代码,并得到“无法访问封闭的流”。

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("username@gmail.com", "username@gmail.com")
{
    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("username@gmail.com", "my_password")
};

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

谢谢!!!

编辑:

为了帮助某人寻找此问题的答案,下面提供了发送电子邮件附件中的pdf文件而无需实际创建文件的代码(感谢Ichiban和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("username@gmail.com", "username@gmail.com")
{
    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("username@gmail.com", "password")

};

smtp.Send(mm);

3
感谢您提出这个问题,这正是我想要的。
Hardwareguy 2010年

1
谢谢你的支持position=0。救了我!
Yisroel M. Olewski 2012年

2
正是我所需要的非常完美,非常感谢!我被困在关闭文档而不是关闭流上:writer.CloseStream = false; 为我清理了。
巴克斯特2014年

2
@Semil在悬而未决的问题上悬赏时,您确实应该以某种方式表明自己错过了答案。
mkl

writer.CloseStream = false; 同样也救了我,在使用iTextSharp将HTML转换为PDF的方法中丢失了它。以前,由于关闭了流,将memorystream传递给我的mail函数失败。谢谢。
亚历克·门科尼

Answers:


81

你有没有尝试过:

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"));

如果我的记忆正确地为我服务,则可以解决先前项目中的类似问题。

参见http://forums.asp.net/t/1093198.aspx


1
set_CloseStream方法仅在Java版本中可用。这是iTextSharp(.NET)
ichiban

抱歉,虽然我使用的版本肯定具有set_CloseStream,但我已经有一段时间没有使用iTextSharp(.NET)了。
brianng

1
更改为writer.CloseStream,并包含相关链接。
brianng

1
Brianng,非常感谢您的帮助。我意识到您和Ichiban确实握住了我的手。谢谢!
Gus Cavalcanti

如果我们让作家活着,那我们writer.Flush()什么时候应该呢?
布莱斯(Blaise)

18

我尝试了brianng发布的代码,它起作用了。只需将代码顶部更改为此:

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*/

3
感谢您抽出宝贵的时间进行验证!
brianng

1
嗨,Ichiban,它可以编译并实际发送带有附件的电子邮件,但是附件的pdf文档带有0kb。您是否真的打开了已发送电子邮件的pdf文件?
Gus Cavalcanti

2
@Gustavo,文件将在Acrobat Viewer中正确打开。它约为900字节。确保保留以下行:memoryStream.Position = 0; 就在doc.Close()之后。我忘了提。(请参阅上面的更新)
ichiban

1
是!十分感谢大家。终于成功了。由于Ichiban的答案基于brianng的答案,因此我认为将brianng的答案标记为正确是合理的。
Gus Cavalcanti

3

您可以先冲洗文档或内存流,然后再将其关闭吗?


嗨,詹姆斯。我这样做了,结果没有改变-我仍然收到“无法访问封闭流”错误。:(还有其他想法吗?
Gus Cavalcanti

3

可能调用doc.Close()处置基础流。尝试删除doc.Close(),而不是该行设置memoryStream.Position = 0;

另外,您可以使用一个临时文件:

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("username@gmail.com", "username@gmail.com")
    {
        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("username@gmail.com", "my_password")
    };

    smtp.Send(mm);
}
finally
{
    File.Delete(tempFilePath);
}

huseyint,我按照您的建议进行了操作,并且发送了pdf文件,但它只有15个字节长。当我尝试打开它时,它已损坏。我觉得我几乎可以接受你的建议。还有其他想法吗?谢谢!
Gus Cavalcanti

然后尝试memoryStream.Flush(); 设定职位之前
huseyint

一样。文件发送几乎是空的并且已损坏。:(
Gus Cavalcanti

您是否尝试过“创建临时文件”?
huseyint

我现在正在处理它,请稍后通知您。谢谢!
Gus Cavalcanti

1

我有同样的问题,我用这篇文章来解决它。在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"));

我认为不是写作

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

只需创建一个新的流

MemoryStream m = new MemoryStream(memoryStream);

然后打电话

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

两者都可以,但是我认为创建新流更好


为什么创建新流会更好?
安迪

不是。这是浪费内存和CPU时间的原因,因为必须将字节从一个字节复制到另一个字节。
Serguei Fedorov

不记得为什么我说更好了。我想我可能想说得更清楚。对不起,刚刚看到了这个。已经很长时间了:)
Zein Sleiman
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.