使用async / await发送电子邮件并删除资源检查条件

时间:2017-08-25 13:17:27

标签: c# async-await

我想使用c#async / await发送电子邮件,程序会根据标记“deleteFile”从计算机中删除附件。无论deleteFile标志的值是什么,电子邮件都成功传递,但是当我将deleteFile设置为true时,我收到以下异常。我必须发送两封单独的电子邮件,我只需要在第二封邮件后删除该文件。

  

发生了'System.IO.IOException'类型的未处理异常   mscorlib.dll中

     

其他信息:进程无法访问该文件   'C:\ Uploads \ TestFile.txt',因为它正由另一个进程使用。

你能帮我解决一下这个问题吗?

我的控制台应用程序代码是:

using System;

namespace SendMailAsyncDemo
{
    class Program
    {
        private static string filePath = @"C:\Uploads\";
        static void Main(string[] args)
        {
            Sender mailSender = new Sender();

            mailSender.SendEmail("myemail@gmail.com", "Async mail with attachment", "Async mail with attachment body goes here ...", filePath + "TestFile.txt", false);

            mailSender.SendEmail("anotheremail@gmail.com.com", "Async mail with attachment", "Async mail with attachment body goes here ...", filePath + "TestFile.txt", true);

            Console.WriteLine("Email sent successfully!!!");

            Console.ReadLine();
        }
    }
}

我有一个Sender类来发送电子邮件:

using System;
using System.IO;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;

namespace SendMailAsyncDemo
{
    public class Sender
    {
        public void SendEmail(string toEmail, string title, string body, string attachmentPath, bool deleteFile = false)
        {
            Task.Factory.StartNew(() =>
            {
                SendEmailAsync(toEmail, title, body, attachmentPath, deleteFile);
            });
        }

        private async void SendEmailAsync(string toEmail, string title, string body, string attachmentPath, bool deleteFile)
        {
            Attachment attachment = null;

            try
            {
                // class to hold all values from the section system.net/mailSettings/smtp in app.config
                MailConfiguration smtpSection = new MailConfiguration();

                using (MailMessage mailMsg = new MailMessage("<" + smtpSection.FromAddress + ">", toEmail))
                {
                    mailMsg.IsBodyHtml = true;
                    mailMsg.Subject = title;
                    mailMsg.SubjectEncoding = Encoding.UTF8;
                    mailMsg.Body = body;
                    mailMsg.BodyEncoding = Encoding.UTF8;

                    if (!string.IsNullOrWhiteSpace(attachmentPath) && File.Exists(attachmentPath))
                    {
                        attachment = new Attachment(attachmentPath);
                        mailMsg.Attachments.Add(attachment);
                    }

                    using (SmtpClient smtpClient = new SmtpClient())
                    {
                        smtpClient.Timeout = 1000000;
                        smtpClient.UseDefaultCredentials = false;

                        if (deleteFile)
                        {
                            smtpClient.SendCompleted += (s, e) =>
                            {
                                attachment.Dispose();
                                File.Delete(attachmentPath);
                            };
                        }
                        await smtpClient.SendMailAsync(mailMsg);                       
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("SendEmail exception: " + ex);
            }
            finally
            {                
                Console.WriteLine("SendEmail done");
            }
        }
    }
}

1 个答案:

答案 0 :(得分:4)

正如评论中所讨论的那样,在维持相同的程序结构的同时,没有简单的方法来解决这个问题。特别是,由于您目前有两个正在进行的电子邮件发送呼叫而彼此不了解,因此无法确定何时可以安全执行删除。第二个Send可以先完成。

我要做的更改 - 我删除了SendEmail并让SendEmailAsync publicTask返回。我还删除了删除后的概念:

    public async Task SendEmailAsync(string toEmail, string title, string body, string attachmentPath)
    {
        try
        {
            // class to hold all values from the section system.net/mailSettings/smtp in app.config
            MailConfiguration smtpSection = new MailConfiguration();

            using (MailMessage mailMsg = new MailMessage("<" + smtpSection.FromAddress + ">", toEmail))
            {
                mailMsg.IsBodyHtml = true;
                mailMsg.Subject = title;
                mailMsg.SubjectEncoding = Encoding.UTF8;
                mailMsg.Body = body;
                mailMsg.BodyEncoding = Encoding.UTF8;

                if (!string.IsNullOrWhiteSpace(attachmentPath) && File.Exists(attachmentPath))
                {
                    Attachment attachment = new Attachment(attachmentPath);
                    mailMsg.Attachments.Add(attachment);
                }

                using (SmtpClient smtpClient = new SmtpClient())
                {
                    smtpClient.Timeout = 1000000;
                    smtpClient.UseDefaultCredentials = false;
                    await smtpClient.SendMailAsync(mailMsg);                       
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("SendEmail exception: " + ex);
        }
        finally
        {                
            Console.WriteLine("SendEmail done");
        }
    }

然后按如下方式更改Main

    static void Main(string[] args)
    {
        Sender mailSender = new Sender();

        var send1 = mailSender.SendEmailAsync("myemail@gmail.com", "Async mail with attachment", "Async mail with attachment body goes here ...", filePath + "TestFile.txt");

        var send2 = mailSender.SendEmailAsync("anotheremail@gmail.com.com", "Async mail with attachment", "Async mail with attachment body goes here ...", filePath + "TestFile.txt");

        Task.WaitAll(send1,send2);
        File.Delete(filePath + "TestFile.txt");

        Console.WriteLine("Email sent successfully!!!");

        Console.ReadLine();
    }

如果这不是Main /如果你正在使用尖端的C#,我还要async使用await几个WaitAll在目前这一点,我得到了for word, count in top_words.items(): print word, count 。它是两个发送共同的最早代码,因此唯一可以确定 的代码片段可以安全地执行删除。