我们有一些(同步)电子邮件代码,它创建一个创建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);
}
}
答案 0 :(得分:5)
您需要使用Dispose
,using
或通过为您的类EmailSender实施一次性模式来处置SmtpClient(这在此更合适,因为您正在使用SmtpClient的生命周期到构造函数中的EmailSender的生命周期。)
这可能会解决此异常。
答案 1 :(得分: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)。