I’ve been looking through the temp directories on my production machines and had realized some overlooked design points in a number of programs; namely the deletion of certain temp files.
One situation that particularly caught my attention was some email attachments that should have been deleted.
Even though the code was actively calling File.Delete() on some email attachments, they were not being deleted.
An error log showed the program was throwing an exception when attempting to delete the files.
The mail was being delivered successfully with no visible flaws to the customer.
I finally decided to write some test code to reproduce the problem that I originally thought was caused by the ZIP compression step right before the mail send.
The problem actually turned out to be I was not calling Dispose() on the attachment resources after the mail send. Most Dot Net classes I use don’t require the explicit calling of a Dispose() method, so I completely bypassed this one until it became necessary. Here’s an example of the solution:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Mail;
…
1: /// <summary>
2: /// Example of simple mailing with attachment and release of attachments.
3: /// </summary>
4: /// <param name="lst_strAttachments">List<string>
5: /// filenames to attach to the email.
6: /// </param>
7: /// <param name="strError">Output of exception text</param>
8: /// <returns>bool: true if no exceptions</returns>
9: public static bool SendMail(List<string> lst_strAttachments, ref string strError)
10: {
11: bool blnRetVal = true;
12: try
13: {
14: string strSubjectBody = "Test Email With Attachment";
15:
16: // Make a basic mail message
17: MailMessage msg = new MailMessage()
18: {
19: Subject = strSubjectBody,
20: Body = strSubjectBody,
21: Priority = MailPriority.Low,
22: From = new MailAddress(EMAIL_ADDRESS_TO_FROM)
23: };
24:
25: msg.To.Add(msg.From); //same as from
26: //http://msdn.microsoft.com/en-us/library/system.net.mail.attachment.aspx
27: lst_strAttachments.ForEach(a => msg.Attachments.Add(new Attachment(a)));
28:
29: (new SmtpClient(SMTP_SERVER_ADDRESS)).Send(msg);
30:
31: // Free the attachment resources
32: msg.Attachments.ToList().ForEach(a => a.Dispose());
33: }
34: catch (Exception exc)
35: {
36: blnRetVal = false;
37: strError = exc.Message;
38: }
39:
40: return blnRetVal;
41: }
…and a small calling program example:
The Zip class is a custom wrapper.
1: static void Main(string[] args)
2: {
3: string strError = "";
4: string strTempFileName = CSampleTempFile.MakeSampleTempFile("One.txt");
5: string strZipFileName = Path.Combine(Path.GetTempPath(),"Test.zip");
6:
7: if (!CZipLib.ZipMove(strZipFileName,
8: new List<string>{strTempFileName}, //list of files (containing 1)
9: ref strError))
10: {
11: Console.WriteLine("Could not zip file {0:G}\n\t: {1:G}",
12: strTempFileName, strError);
13: return;
14: }
15:
16: if (!SendMail(new List<string>{strZipFileName}, ref strError))
17: {
18: Console.WriteLine("Could not send mail: " + strError);
19: return;
20: }
21:
22: File.Delete(strZipFileName); //<--WORKS!
23: }