Skip to main content
 首页 » 编程设计

C#之在发送到电子邮件时附加 FileStream System.ObjectDisposedException

2024年02月04日38linjiqin

你好,

我正在尝试将文件流文件附加到电子邮件发送附件。场景是,我需要使用 FileStream 创建一个文件,然后将其附加到我的电子邮件中。

到目前为止,这是我的示例代码:

创建文件:

public FileStream CreateFileStream(){ 
    using (var ms = new MemoryStream()) 
    { 
    var writer = new StreamWriter(ms); 
 
    writer.WriteLine("file content blah blah blahh"); 
    writer.Flush(); 
 
    //You have to rewind the MemoryStream before copying 
    ms.Seek(0, SeekOrigin.Begin); 
 
       using (var fs = new FileStream("Filename.txt", FileMode.Create)) 
       { 
          ms.CopyTo(fs); 
          return fs; 
       } 
    } 
} 

这是我发送邮件的示例代码

// attachment 
var fileStreamFile = dto.FileStreamFile; 
 
var contentType = new ContentType(MediaTypeNames.Text.Plain); 
var attach = new Attachment(dto.FileStreamFile, contentType); 
attach.ContentDisposition.FileName = "File.txt"; 
 
mail.Attachments.Add(attach); 
... 
// code for sending here 
... 
dto.FileStreamFile.Dispose(); // for disposing File Stream 

fileStreamFile 不为空,但它抛出一个错误,指出,

Handle = 'dto.FileStreamFile.Handle' 引发了 'System.ObjectDisposedException' 类型的异常

当我注释掉附加代码时,电子邮件的发送仍然正常。当我包含用于附加 FileStream

的代码时,电子邮件发送失败

有什么帮助吗?提前谢谢你

请您参考如下方法:

你的代码

using (var fs = new FileStream("Filename.txt", FileMode.Create)) 
{ 
    ms.CopyTo(fs); 
    return fs; // you are returning here 
} // hang on, this is a using statement which will dispose fs! 

将翻译成这个

FileStream fileStream = new FileStream("Filename.txt", FileMode.Create); 
try 
{ 
   return fileStream; 
} 
finally 
{ 
   if (fileStream != null) 
   { 
      ((IDisposable)fileStream).Dispose(); 
   } 
} 

请务必注意,如果您 return在try finally ,它将返回值存储在局部变量中,在finally之后返回.看起来像这样

FileStream fileStream = new FileStream("Filename.txt", FileMode.Create); 
try 
{ 
   temp = fileStream; 
} 
finally 
{ 
   if (fileStream != null) 
   { 
      ((IDisposable)fileStream).Dispose(); 
   } 
} 
 
return temp; 

我们可以查看IL 看看发生了什么

IL_0000: ldstr "someFile" 
IL_0005: ldc.i4.2 
IL_0006: newobj instance void [mscorlib]System.IO.FileStream::.ctor(string, valuetype[mscorlib]System.IO.FileMode) 
// stloc.0 Pops the current value from the top of the evaluation stack and stores it in the  
// local variable list at a specified index. This is your fs reference 
IL_000b: stloc.0  
   .try 
{ 
   // ldloc.0 Loads the local variable at a specific index onto the evaluation stack. 
   // This is your fs reference 
   IL_000c: ldloc.0 
   // stloc.1 Pops the current value from the top of the evaluation stack and stores it in  
   // the local variable list at a specified index. This is your fs reference 
   IL_000d: stloc.1 
   IL_000e: leave.s IL_001a 
} // end .try 
finally 
{ 
   IL_0010: ldloc.0 
   IL_0011: brfalse.s IL_0019      
   IL_0013: ldloc.0 
   // oh no we just Disposed fs!!! 
   IL_0014: callvirt instance void [mscorlib]System.IDisposable::Dispose() 
   IL_0019: endfinally 
} // end handler 
 
// ldloc.1 Loads the local variable at a specific index onto the evaluation stack. 
// This is your fs reference 
IL_001a: ldloc.1 
//ret Returns from the current method, pushing a return value (if present) from  
//the callee's evaluation stack onto the caller's evaluation stack. 
IL_001b: ret 

简而言之,不要返回 IDisposable来自 using 的引用声明,因为它将被处置。

您需要创建 FileStream (没有 using )和 Dispose它在另一个上下文中,或重构您的代码。

更新

But my email sending doesn't work after I put a using statement covering the sending of email with stream

你可能把这个复杂化了,试试这样的东西

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@example.com", "you@example.com", "Just testing", "See attachment...")) 
         { 
            writer.WriteLine("file content blah blah blahh"); 
            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); 
         }