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

を使用してSmtpClientDisposeを破棄するか、クラス EmailSender の破棄可能なパターンを実装する必要がありusingます (コンストラクターで SmtpClient の有効期間を EmailSender の有効期間に結び付けているため、ここではより適切です)。

それはこの例外を解決するかもしれません。

于 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)
        }
    }
}

コンストラクターでクライアントを作成する理由は実際にはありません。

また、 nullの場合ではArgumentNullExceptionなく、クラスがスローするように変更しました。空は多くを語らない..ExceptionfromMailAddressException

アップデート

コードは、送信 (および smtpclient の再利用) にスレッド プール スレッドを使用するようになりました。

于 2013-05-08T10:26:58.697 に答える