两种通过SmtpClient异步发送电子邮件的方法,结果不同

Joh*_*n L 8 c# asynchronous smtpclient

这里简单的概念.这适用于使用MVC 3和Entity Framework 4构建的站点.用户在站点上注册后,会向其电子邮件地址发送一封电子邮件.我首先使用SmtpClient.Send()实现它,它工作正常.然后我明白了尝试异步发送电子邮件.我遇到了我尝试过的两种异步方法的问题.

第一个实现(来自这个未回答的帖子:https://stackoverflow.com/questions/7558582/how-to-dispose-using-smtpclient-send-and-asynccallback):

public bool Emailer(){
    .
    .
    .
    using (var smtpClient = new SmtpClient())
    {
        smtpClient.EnableSsl = true;
        smtpClient.Host = "smtp.gmail.com";
        smtpClient.Port = 587;
        smtpClient.UseDefaultCredentials = false;
        smtpClient.Credentials = new NetworkCredential("myaddress@gmail.com", "mypassword");

        var sd = new SendEmailDelegate(smtpClient.Send);
        var cb = new AsyncCallback(SendEmailResponse);
        sd.BeginInvoke(message, cb, sd);

        return true;
    }
}

private delegate void SendEmailDelegate(System.Net.Mail.MailMessage m);

private static void SendEmailResponse(IAsyncResult ar)
{
    try
    {
        SendEmailDelegate sd = (SendEmailDelegate)(ar.AsyncState);
        sd.EndInvoke(ar); // "cannot access a disposed object" errors here
    }
    catch (Exception e)
    {
        _logger.WarnException("Error on EndInvoke.", e);
    }
}
Run Code Online (Sandbox Code Playgroud)

这有一半的时间.另一半我会在CallBack中收到"无法访问已处置对象"错误.

下一个实现(来自具有良好声誉的成员:在.NET 4.0下使用SmtpClient,SendAsync和Dispose的最佳实践):

var smtpClient = new SmtpClient();
smtpClient.EnableSsl = true;
smtpClient.Host = "smtp.gmail.com";
smtpClient.Port = 587;
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = new NetworkCredential("myaddress@gmail.com", "mypassword");

smtpClient.SendCompleted += (s, e) =>
    {
        smtpClient.Dispose();
        message.Dispose();
    };
smtpClient.SendAsync(message, null);
Run Code Online (Sandbox Code Playgroud)

有了这个实现,我没有得到任何错误,但是当执行smtpClient.SendAsync()时,在调试模式下有明显更长的延迟(~5秒),这使我认为它不是异步发送的.

问题:

1)导致"处置对象"错误的第一种方法出了什么问题?

2)第二个实现是否存在导致电子邮件不异步发送的问题?5秒延迟是无意义的吗?

可能还需要注意的是,虽然该网站不需要支持发送大量电子邮件(仅限用户注册,选择加入新闻通讯等),但我们预计将来会有大量用户,因此我决定异步发送电子邮件.

谢谢.

Mit*_*dir 7

由于USING-block,你的第一种方法无法正常工作.使用块结束后,将释放SmtpClient对象.因此,您无法在事件处理程序中访问它.


das*_*rin 5

提示:1 - 不要对MailMessage对象使用"using block",它会在邮件发送之前处理您的对象,
在SmtpClient.SendCompleted事件上发送2-dispose MailMessage对象:

smtpClient.SendCompleted += (s, e) =>
    {
        message.Dispose();
    };
Run Code Online (Sandbox Code Playgroud)

用于smtpClient对象的3组SendCompletedEventHandler

smtpClient.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);
Run Code Online (Sandbox Code Playgroud)

4个代码:

private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
    {
        // Get the unique identifier for this asynchronous operation.
        String token = (string)e.UserState;

        if (e.Cancelled)
        {
            //write your code here
        }
        if (e.Error != null)
        {
            //write your code here
        }
        else //mail sent
        {
            //write your code here
        }

        mailSent = true;
    }
Run Code Online (Sandbox Code Playgroud)