tags:

views:

688

answers:

3

Hi,

I'm having issues with a bit of code that I am writing in c#.

I am sending a document using the MailMessage and SMTP components. I copy the files that I wish to send to a temp directory such as c:\temp, loop through the documents and attach them to the email.

The email sends fine, however when I try to delete the files from the temp directory, I get the following error:

The process can not access the file because it is being used by another process

I can't understand why this is happening. Below is the code that processes the documents

public void sendDocument(String email, string barcode, int requestid)
    {

        string tempDir = @"c:\temp";

        //first we get the document information from the database.
        Database db = new Database(dbServer, dbName, dbUser, dbPwd);

        List<Document> documents = db.getDocumentByID(barcode);
        int count = 0;
        foreach (Document doc in documents)
        {
            string tempPath = tempDir + "\\" + doc.getBarcode() + ".pdf";
            string sourcePath = doc.getMachineName() + "\\" + doc.getFilePath() + "\\" + doc.getFileName();

            //we now copy the file from the source location to the new target location
            try
            {
                //this copies the file to the folder
                File.Copy(sourcePath, tempPath, false);

            }
            catch (IOException ioe)
            {
                count++; 

                //the file has failed to copy so we add a number to the file to make it unique and try
                //to copy it again.
                tempPath = tempDir + "\\" + doc.getBarcode() + "-" + count + ".pdf";
                File.Copy(sourcePath, tempPath, false);

            }

            //we now need to update the filename in the to match the new location
            doc.setFileName(doc.getBarcode() + ".pdf");                

        }

        //we now email the document to the user.
        this.sendEmail(documents, email, null);

        updateSentDocuments(documents, email);

        //now we update the request table/
        db.updateRequestTable(requestid);


        //now we clean up the documents from the temp folder.
        foreach (Document doc in documents)
        {
            string path = @"c:\temp\" + doc.getFileName();
            File.Delete(path);
        }

    }

I would of thought that the this.sendEmail() method would of sent the email before returning to the sendDocument method, as I think it is the smtp object that is causing the deletes to fail.

This is the sendEmail method:

public void sendEmail(List<Document> documents, String email, string division)
    {
        String SMTPServer = null;
        String SMTPUser = null;
        String SMTPPwd = null;
        String sender = "";
        String emailMessage = "";

        //first we get all the app setting used to send the email to the users
        Database db = new Database(dbServer, dbName, dbUser, dbPwd);

        SMTPServer = db.getAppSetting("smtp_server");
        SMTPUser = db.getAppSetting("smtp_user");
        SMTPPwd = db.getAppSetting("smtp_password");
        sender = db.getAppSetting("sender");
        emailMessage = db.getAppSetting("bulkmail_message");

        DateTime date = DateTime.Now;

        MailMessage emailMsg = new MailMessage();

        emailMsg.To.Add(email);

        if (division == null)
        {
            emailMsg.Subject = "Document(s) Request - " + date.ToString("dd-MM-yyyy");
        }
        else
        {
            emailMsg.Subject = division + " Document Request - " + date.ToString("dd-MM-yyyy");
        }

        emailMsg.From = new MailAddress(sender);
        emailMsg.Body = emailMessage;

        bool hasAttachements = false;

        foreach (Document doc in documents)
        {

            String filepath = @"c:\temp\" + doc.getFileName();

            Attachment data = new Attachment(filepath);
            emailMsg.Attachments.Add(data);

            hasAttachements = true;


        }

        SmtpClient smtp = new SmtpClient(SMTPServer);

        //we try and send the email and throw an exception if it all goes tits.
        try
        {
            if (hasAttachements)
            {
                smtp.Send(emailMsg);
            }
        }
        catch (Exception ex)
        {
            throw new Exception("EmailFailure");
        }


    }

How to I get around this problem with a process hogging the file I wish to delete.

I can delete the file(s) once the application finishes.

A: 

The first step is to figure out what process is holding onto the file in question. I would grab the SysInternals toolkit and use the handle.exe command to determine what process is holding onto the file.

Without knowing what process has the file open, there is no way to fix this problem.

Sysinternals Link: http://technet.microsoft.com/en-us/sysinternals/default.aspx

JaredPar
thanks for the link to these tools... very useful...
Grant Collins
+3  A: 

You're email message isn't being Disposed, try disposing it after you've sent it:

 try
 {
      if (hasAttachements)
      {
          smtp.Send(emailMsg);         
      }
 }  
 catch ...
 finally
 {
      emailMsg.Dispose();
 }
Joseph
A: 

Here's a trick I just discoverred, which will hopefully be of use to other folk? Before adding attachments to a message, create the attachment in a using wrapper. This ensures it gets disposed of correctly, allowing the file to be successfully deleted. I'm not sure if the send also needs to be in this loop; (when I tested, emails didn't get through at first, then half an hour later I got flooded, so decided to leave testing for a time when the network was a little calmer).

using (Attachment attachment = new Attachment(filename))
{
    message.Attachments.Add(attachment);
    client.SendAsync(message, string.Empty);
}
File.Delete(filename);

Works OK for me anyway :)

Good luck,

JB