在C#中,将MemoryStream中的文件附加到MailMessage中。
问题的原因是在将一个内存流作为附件添加到邮件消息中时,需要确保在消息发送之前不要释放StreamWriter和底层流。另外,需要将流的位置设置为0,以便从写入的开头开始读取。此外,设置MIME类型可以帮助接收方的邮件客户端正确处理附件。
解决方法是在发送邮件消息之前不要释放StreamWriter和底层流,以避免"ObjectDisposedException: Cannot access a closed Stream"异常。另外,需要将流的位置设置为0,以便从写入的开头开始读取。可以使用stream.Position = 0;
来实现。此外,可以设置附件的MIME类型,以便接收方的邮件客户端正确处理附件。
以下是一个简化的示例代码,用于将内存中的字符串作为电子邮件附件发送(在这个特定的示例中是一个CSV文件):
using (var stream = new MemoryStream()) using (var writer = new StreamWriter(stream)) // using UTF-8 encoding by default using (var mailClient = new SmtpClient("localhost", 25)) using (var message = new MailMessage("me.com", "you.com", "Just testing", "See attachment...")) { writer.WriteLine("Comma,Separated,Values,..."); writer.Flush(); stream.Position = 0; // read from the start of what was written message.Attachments.Add(new Attachment(stream, "filename.csv", "text/csv")); mailClient.Send(message); }
以上是对问题的原因和解决方法的整理和总结。通过确保正确使用using语句块、设置流的位置以及设置附件的MIME类型,可以成功地将内存流作为附件添加到邮件消息中。
问题原因:
在这段代码中,作者想要确认当MailMessage对象或Attachment对象被释放时,它们是否会同时释放内部的MemoryStream流。通过对MailMessage对象进行Dispose操作后,发现与之相关联的流也被释放了。因此,只要正确地释放MailMessage对象,创建附件时使用的流就不需要额外处理。
解决方法:
为了证实这一行为,作者进行了一个简单的测试。测试中,首先创建了一个MemoryStream对象,然后将其作为附件添加到MailMessage对象中。通过判断ContentStream属性与原始的MemoryStream对象是否相同,可以确定流是否被正确地传递给了附件。接着,通过调用Dispose方法释放MailMessage对象,并尝试访问原始的MemoryStream对象,发现会抛出"Cannot access a closed Stream."的异常。这表明在正确地释放MailMessage对象后,相关的流也被正确地释放了。
文章内容如下:
在使用C#中的MailMessage时,如何将一个内存流(MemoryStream)的文件作为附件添加到邮件中呢?经过实验,发现当MailMessage对象被Dispose时,附件中使用的内存流也会被释放。只要正确地释放MailMessage对象,创建附件时使用的流就不需要额外处理。 下面是一个简单的测试代码示例: MailMessage mail = new MailMessage(); //从文件创建一个内存流(MemoryStream)用于测试 MemoryStream ms = new MemoryStream(File.ReadAllBytes(@"C:\temp\test.gif")); mail.Attachments.Add(new System.Net.Mail.Attachment(ms, "test.gif")); if (mail.Attachments[0].ContentStream == ms) Console.WriteLine("Streams are referencing the same resource"); Console.WriteLine("Stream length: " + mail.Attachments[0].ContentStream.Length); //在发送邮件后,按照规范释放MailMessage对象 mail.Dispose(); //--或者你也可以直接释放附件本身 //mm.Attachments[0].Dispose(); Console.WriteLine("This will throw a 'Cannot access a closed Stream.' exception: " + ms.Length); 通过这个简单的测试,我们可以得出结论:当MailMessage对象被Dispose时,与之相关联的流也会被正确地释放。因此,我们可以放心地在使用MailMessage对象后,直接释放该对象而不需要额外处理相关的流。 希望这个行为能够被官方文档所记录。虽然作者进行了测试并验证了这种行为,但如果没有官方文档的支持,很难相信这种行为会一直存在。不管怎样,感谢作者进行了测试。 在C#中,将内存流作为附件添加到MailMessage对象中的方法非常简单。只需要将内存流作为Attachment对象的参数,然后将该Attachment对象添加到MailMessage对象的Attachments集合中即可。在正确地使用MailMessage对象后,只需要释放该对象即可,不需要额外处理相关的流。这种行为可能没有被官方文档记录,但通过测试可以确认其有效性。
问题的原因是在将MemoryStream附加到MailMessage时需要确保MemoryStream的位置为0,以便正确读取文件内容。在给MemoryStream创建附件之前,需要添加代码ms.Position = 0;来将位置重置为0。
解决方法是在创建MailAttachment之前,添加ms.Position = 0;代码来重置MemoryStream的位置。
以下是完整的代码示例:
System.IO.MemoryStream ms = new System.IO.MemoryStream(); System.IO.StreamWriter writer = new System.IO.StreamWriter(ms); writer.Write("Hello its my sample file"); writer.Flush(); writer.Dispose(); ms.Position = 0; System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Text.Plain); System.Net.Mail.Attachment attach = new System.Net.Mail.Attachment(ms, ct); attach.ContentDisposition.FileName = "myFile.txt"; // 发送带附件的邮件 // 发送邮件后 ms.Close();
在编辑1中,提到了可以使用System.Net.Mime.MimeTypeNames来指定其他文件类型,例如System.Net.Mime.MediaTypeNames.Application.Pdf。根据Mime类型,需要在FileName中指定正确的扩展名,例如"myFile.pdf"。在System.Net.Mime.ContentType的参数中,需要使用System.Net.Mime.MediaTypeNames.Application.Pdf来传递PDF文件类型。
在编辑2中,提到了在解决方案中writer.Dispose()的位置不正确,需要将其放到其他位置。除此之外,其他部分都是一个很好的示例。
最后,还提到了在创建附件之前,应该有ms.Position = 0;的代码来确保MemoryStream的位置为0。