开发者

Stream closed error when adding attachment to MailMessage

I use the following code to attach a file to an email message.

msg = new MailMessage();

    using (strMem = new MemoryStream((byte[])attDr["filedata"]))
    {
        using (st开发者_StackOverflow中文版rWriter = new StreamWriter(strMem))
        {
            strWriter.Flush(); strMem.Position = 0;
            using (attachment = new Attachment(strMem, attDr["filename"].ToString()))
            {
                msg.Attachments.Add(attachment);
            }
        }
    }

...
...
msg.Send();  //Error: System.ObjectDisposedException: Cannot access a closed Stream.

The error message is: //Error: System.ObjectDisposedException: Cannot access a closed Stream

Im guessing that the "USING" statement closes the stream when exiting the block. But why doesnt "Attacments.Add()" make its own copy of the stream?


The Send() method is going to access the attachments to embed them into the mail message. That goes kaboom here, the memory stream was disposed. You need to move the Send() call inside of the using statements so the stream doesn't get disposed until after the message is sent.

Mentioning that using isn't necessary here because a memory stream doesn't have any unmanaged resources that need to be disposed always gets me into trouble at SO. So I won't bring that up.


One solution I found to this when I was dealing with a scenario where the MailMessage was being created separate from the sending and potentially with multiple attachments was to use a List of MemoryStream objects

// Tuple contains displayName and byte[] content for attachment in this case
List<Tuple<string,byte[]>> attachmentContent;
MailMessage email = BuildNativeEmail(requestObject, out attachmentContent);
List<MemoryStream> streams = new List<MemoryStream>();
foreach(Tuple<string,byte[]> attachment in attachmentContent)
{
    MemoryStream m = new MemoryStream(attachment.Item2);
    email.Attachments.Add(new System.Net.Mail.Attachment(m, attachment.Item1));
    streams.add(m);
}

// client represents a System.Net.Mail.SmtpClient object
client.Send(email);

foreach(MemoryStream stream in streams)
{
    stream.Dispose();
}


Yes.Its true.Using statement closes the stream when exiting the block.

Don't use "Using" statement.After sending email call dispose() method for Attachments.

...
...
msg.Send();

msg.Attachments.ToList().ForEach(x => x.ContentStream.Dispose());

You can also use the same way for AlternateView.

...
...
msg.AlternateViews.Add(alternateView);

...
msg.Send();
...
if (alternateView != null) {
    mail.AlternateViews.Dispose();
}


Use :

using (strMem = new MemoryStream((byte[])attDr["filedata"]))
{
    using (strWriter = new StreamWriter(strMem))
    {
        strWriter.Flush(); strMem.Position = 0;
        using (attachment = new Attachment(attDr["filename"].ToString()))
        {
            strMem.CopyTo(attachment.ContentStream);
            msg.Attachments.Add(attachment);
        }
    }
}


Put the using on the MailMessage, it will internally dispose of the streams that make up the attachments

using(var msg = new MailMessage())
{
    ...
    ...
    var attachment = new Attachment(strMem, filename,contentType);
    msg.Attachments.Add(attachment);
    ...
    ...             
    msg.Send();
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜