1. Welcome to TechPowerUp Forums, Guest! Please check out our forum guidelines for info related to our community.

StmpClient Problem in C#

Discussion in 'Programming & Webmastering' started by Kreij, Mar 12, 2010.

  1. Kreij

    Kreij Senior Monkey Moderator Staff Member

    Joined:
    Feb 6, 2007
    Messages:
    13,881 (5.08/day)
    Thanks Received:
    5,615
    Location:
    Cheeseland (Wisconsin, USA)
    I create a file on disk from my app, and then I want to send the file via e-mail.
    This works fine by creating an SmtpClient and using the Send() method.

    When the send completed I want to delete the file as there is no reason to save it any longer.

    Code:
    .... Code for creating file
    SmtpClient _Client = new SmtpClient();
    .... code for client configuration
    
    try
    {
        _Client.Send(myFile);
    }
    catch()
    {
         ... handle an exception
    }
    
    System.IO.File.Delete(myFile);
    
    The Send() method is supposed to block until finished, but this throws a "File in use by another process" exception on the Delete method.

    So I then tried running the whole thing in a BackgroundWorker and then doing the file delete in the RunWorkerCompleted event. This too throws the same error.

    It's seems that SmtpClient process still has a handle attached to the thread, but I'm not sure why it is not letting it go when it's done with the send.

    Any ideas?


    Oops .. title was supposed to be SmtpClient not StmpClient.
    Last edited: Mar 12, 2010
  2. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    13,354 (6.31/day)
    Thanks Received:
    3,367
    Location:
    IA, USA
    I would make a second thread and public List<string>. The second worker thread just loops every five seconds or so and attempts to delete the files in the List<string> collection. If it succeeds, remove it from the list, if it fails, keep it in the list until next time.

    I would only use this approach if the file is in a temp dir where it is a copy and won't be missed.


    If that doesn't work either, instead of deleting using File.Delete, launch cmd.exe with the del [path] command. That worked in situations where File.Delete wouldn't.
    Kreij says thanks.
    Crunching for Team TPU
  3. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    13,354 (6.31/day)
    Thanks Received:
    3,367
    Location:
    IA, USA
    Oh, if Send causes the thread to pause until complete, you shouldn't need the second thread. You might just need to have the shell delete the file instead of your app.

    I know I used cmd to copy a file that another application had a write stream open on. .NET would refuse to touch it but cmd didn't complain. It copied the file and then I could open a read stream on the copy and delete the copy once I was done.


    I guess the question is: does the SMTP Client ever release the file (at least within reason)?
    Crunching for Team TPU
  4. regexorcist

    regexorcist New Member

    Joined:
    Feb 1, 2010
    Messages:
    178 (0.11/day)
    Thanks Received:
    46
    Location:
    ~/
    Kreij says thanks.
  5. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    13,354 (6.31/day)
    Thanks Received:
    3,367
    Location:
    IA, USA
    According to that, it won't be fixed until .NET 4.0 (Visual Studio 2010) which isn't officially out yet.
    Crunching for Team TPU
  6. Kreij

    Kreij Senior Monkey Moderator Staff Member

    Joined:
    Feb 6, 2007
    Messages:
    13,881 (5.08/day)
    Thanks Received:
    5,615
    Location:
    Cheeseland (Wisconsin, USA)
    That seems to be a different issue (not gracefully releasing the connection using QUIT).
    I don't know how long SmtpClient keeps a handle on the file, and the rather frustrating part is that there is no good way in .Net to check for "file in use."

    It seems that many people simply try to open a stream to the file and if it throws an exception because it is in use, retry until it succeeds, and then do whatever they want to do with the file.

    This is a rather "expensive" way of checking to see if a file is in use.
    You can also get a list of process handles, but you have to leave the realm of managed code to do it and this too seems like overkill. It's kind of like stopping at every house in the neighborhood to see if your friend lives there when you have his address in your pocket.

    I can code around this by deleting the files at a different point in time, like looking for leftover files from a previous module run when the module starts, but that just doesn''t sit too well with my "clean up when your done" programming mentality. :D

    Maybe I will just launch a GC thread at application start that periodically (once every 5 minutes or so) checks for the temporary files and deletes them if it can. (shrug)

    @Ford : You're getting dangerously close to 5k posts. :toast: Do you have a custom title picked out yet?
    Last edited: Mar 13, 2010
  7. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    13,354 (6.31/day)
    Thanks Received:
    3,367
    Location:
    IA, USA
    Opening a file stream isn't expensive. I'm pretty sure it comes straight from the NTFS table and it doesn't seek the hard drive unless you start reading or writing.

    This is what I'd do (pseudocode):

    Code:
    internal volitile List<string> _DeleteFiles = new internal List<string>();
    private Thread _Thread = null;
    public void Start()
    {
      _Thread = new Thread(Worker);
      _Thread.Start();
    }
    public void Stop()
    {
      if (_Thread != null)
        _Thread.Abort();
    }
    
    public void Worker()
    {
      while (true)
      {
        for (int i = _DeleteFiles.Count - 1; i >= 0; i--)
        {
          try
          {
            File.Delete(_DeleteFiles[i]);
            _DeleteFiles.RemoveAt(i);
          }
          catch  { }
        }
        Thread.Sleep(5000);
      }
    }
    If you got a file you want to delete, add it to the _DeleteFiles collection.
    Crunching for Team TPU
  8. CrackerJack

    CrackerJack

    Joined:
    Dec 13, 2007
    Messages:
    2,702 (1.11/day)
    Thanks Received:
    448
    Location:
    East TN
    This might be too simple... but have you tried closing myfile?

    Code:
    .... Code for creating file
    SmtpClient _Client = new SmtpClient();
    .... code for client configuration
    
    try
    {
        _Client.Send(myFile);
    }
    catch()
    {
         ... handle an exception
    }
    System.IO.File.Close(myfile);
    {
    System.IO.File.Delete(myFile);
  9. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    13,354 (6.31/day)
    Thanks Received:
    3,367
    Location:
    IA, USA
    myFile is of type MailMessage (so File.Delete(myFile) will always error--can't delete MailMessage). So the files he would need to delete are probably under myFile.Attachments (an AttachmentCollection), no?

    This has an example:
    http://msdn.microsoft.com/en-us/library/system.net.mail.mailmessage.attachments.aspx

    Code:
                MailMessage message = new MailMessage(
                   "jane@contoso.com",
                   "ben@contoso.com",
                   "Quarterly data report.",
                   "See the attached spreadsheet.");
    
                // Create  the file attachment for this e-mail message.
                Attachment data = new Attachment(file, MediaTypeNames.Application.Octet);
                // Add time stamp information for the file.
                ContentDisposition disposition = data.ContentDisposition;
                disposition.CreationDate = System.IO.File.GetCreationTime(file);
                disposition.ModificationDate = System.IO.File.GetLastWriteTime(file);
                disposition.ReadDate = System.IO.File.GetLastAccessTime(file);
                // Add the file attachment to this e-mail message.
                message.Attachments.Add(data);
    What exactly are you trying to delete? If there isn't attachments, myFile = null would suffice.
    Last edited: Mar 13, 2010
    Crunching for Team TPU
  10. Kreij

    Kreij Senior Monkey Moderator Staff Member

    Joined:
    Feb 6, 2007
    Messages:
    13,881 (5.08/day)
    Thanks Received:
    5,615
    Location:
    Cheeseland (Wisconsin, USA)
    Ford is correct. It's a PDF file that is created using the ReportDocument.ExportToDisk() method and then added as an attachment to the MailMessage.

    @Cracker ... There is no System.IO.File.Close() method.
  11. CrackerJack

    CrackerJack

    Joined:
    Dec 13, 2007
    Messages:
    2,702 (1.11/day)
    Thanks Received:
    448
    Location:
    East TN
    o ok so it's physical never on the HD then? hince can't do the file.close method? never work with reportdocument or mailmessage yet.
  12. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    13,354 (6.31/day)
    Thanks Received:
    3,367
    Location:
    IA, USA
    So is ExportToDisk or the Attachment not releasing the file? Can you try deleting the file after performing ExportToDisk to rule that out?
    Last edited: Mar 15, 2010
    Crunching for Team TPU
  13. Kreij

    Kreij Senior Monkey Moderator Staff Member

    Joined:
    Feb 6, 2007
    Messages:
    13,881 (5.08/day)
    Thanks Received:
    5,615
    Location:
    Cheeseland (Wisconsin, USA)
    I haven't had time to work on this problem, but thanks for the input guys.

    I am assuming (I know, that's bad) that ExportToDisk() is releasing the file otherwise SmtpClient would have problems opening it to send it as an attachment.

    Of course, with some if the internals of .Net it's anyone's guess. :D
  14. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    13,354 (6.31/day)
    Thanks Received:
    3,367
    Location:
    IA, USA
    It depends on how Attachments work. If it is just copying a link and not the bytes, ExportToDisk() might be the culprit.
    Crunching for Team TPU

Currently Active Users Viewing This Thread: 1 (0 members and 1 guest)

Share This Page