9

我们有一些(同步)电子邮件代码,它创建了一个创建 SmtpClient 的类,然后发送一封电子邮件。SmtpClient 没有被重用;但是我们时不时会遇到以下异常:

System.Web.HttpUnhandledException (0x80004005): Exception of type 'System.Web.HttpUnhandledException' was thrown. ---> System.InvalidOperationException: An asynchronous call is already in progress. It must be completed or canceled before you can call this method.
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   at EmailSender.SendMail(MailAddress fromMailAddress, string to, String subject, String body, Boolean highPriority) in ...\EmailSender.cs:line 143

代码如下所示:

// ...
var emailSender = new EmailSender();
emailSender.SendMail(toEmail, subject, body, true);
// emailSender not used past this point
// ...

public class EmailSender : IEmailSender
{
    private readonly SmtpClient smtp;

    public EmailSender()
    {
        smtp = new SmtpClient();
    }

    public void SendMail(MailAddress fromMailAddress, string to, string subject, string body, bool highPriority)
    {
        if (fromMailAddress == null)
            throw new Exception();
        if (to == null)
            throw new ArgumentException("No valid recipients were supplied.", "to");

        // Mail initialization
        var mailMsg = new MailMessage
        {
            From = fromMailAddress,
            Subject = subject,
            Body = body,
            IsBodyHtml = true,
            Priority = (highPriority) ? MailPriority.High : MailPriority.Normal
        };

        mailMsg.To.Add(to);


        smtp.Send(mailMsg);
    }
}
4

2 回答 2

5

您需要使用或通过为您的类 EmailSender 实现一次性模式来处理SmtpClient(这里更合适,因为您将 SmtpClient 的生命周期与构造函数中的 EmailSender 的生命周期联系起来。)Disposeusing

这可能会解决这个异常。

于 2013-05-08T10:27:27.747 回答
1

我的猜测是,它的SmtpClient设计目的不是同时发送多条消息。

我会改为这样更改课程:

public class EmailSender : IEmailSender
{
    Queue<MailMessage> _messages = new Queue<MailMessage>();
    SmtpClient _client = new SmtpClient();

    public EmailSender()
    {
    }

    public void SendMail(MailAddress fromMailAddress, string to, string subject, string body, bool highPriority)
    {
        if (fromMailAddress == null)
            throw new ArgumentNullException("fromMailAddress");
        if (to == null)
            throw new ArgumentException("No valid recipients were supplied.", "to");

        // Mail initialization
        var mailMsg = new MailMessage
        {
            From = fromMailAddress,
            Subject = subject,
            Body = body,
            IsBodyHtml = true,
            Priority = (highPriority) ? MailPriority.High : MailPriority.Normal
        };

        mailMsg.To.Add(to);

        lock (_messages)
        {
            _messages.Enqueue(mailMsg);
            if (_messages.Count == 1)
            {
                ThreadPool.QueueUserWorkItem(SendEmailInternal);
            }
        }
    }

    protected virtual void SendEmailInternal(object state)
    {
        while (true)
        {
            MailMessage msg;
            lock (_messages)
            {
                if (_messages.Count == 0)
                    return;
                msg = _messages.Dequeue();
            }

            _client.Send(msg)
        }
    }
}

因为真的没有理由在构造函数中创建客户端。

我也进行了更改,以便类抛出ArgumentNullException而不是Exception如果fromMailAddress为空。一个空话Exception不多说。。

更新

该代码现在使用线程池线程进行发送(并重用 smtpclient)。

于 2013-05-08T10:26:58.697 回答