当用户在我的网站上注册时,我不明白为什么我需要让他“等待”smtp通过,这样他才能收到激活电子邮件。
我决定异步启动这段代码,这是一次冒险。
假设我有一个方法,比如:
private void SendTheMail() { // Stuff }
我的第一次..是线程化。我这样做了:
Emailer mailer = new Emailer();
Thread emailThread = new Thread(() => mailer.SendTheMail());
emailThread.Start();
这行得通..。直到我决定测试它的错误处理能力。我故意破坏了我的web.config中的SMTP服务器地址,并尝试了它。可怕的结果是IIS基本上在w3wp.exe上出现了一个未处理的异常错误(这是一个windows错误!有多极端...)ELMAH (我的错误记录器)没有捕捉到它,IIS被重启,所以网站上的任何人都会删除他们的会话。完全不能接受的结果!
我的下一个想法是对异步委托做一些研究。这似乎工作得更好,因为异常是在异步委托中处理的(与上面的线程示例不同)。然而,我担心如果我做错了,或者我可能导致了内存泄漏。
这就是我要做的:
Emailer mailer = new Emailer();
AsyncMethodCaller caller = new AsyncMethodCaller(mailer.SendMailInSeperateThread);
caller.BeginInvoke(message, email.EmailId, null, null);
// Never EndInvoke...
我这样做对吗?
发布于 2012-01-06 20:50:44
我在这里得到了很多很好的建议...比如确保记得使用IDisposable (我完全不知道)。我还意识到在另一个线程中手动捕获错误是多么重要,因为没有上下文--我一直在研究一种理论,即我应该让ELMAH处理所有事情。此外,进一步的探索使我意识到我也忘记了在邮件消息上使用IDisposable。
作为对Richard的回应,尽管我看到线程解决方案可以工作(正如我在第一个示例中建议的那样),但只要我捕捉到错误...如果不能捕捉到这个错误,IIS就会完全爆炸,这一事实仍然有些可怕。这告诉我,ASP.NET/IIS从来没有让您这样做的意思...这就是为什么我倾向于继续使用.BeginInvoke/委托,因为这不会在出现问题时搞乱IIS,而且在ASP.NET中似乎更受欢迎。
在对ASawyer的回应中,我完全惊讶于客户端中内置了一个.SendAsync。我尝试了一段时间的解决方案,但它似乎没有为我做的把戏。尽管我可以跳过执行SendAsync的代码的客户端,但页面仍然会“等待”,直到SendCompleted事件完成。我的目标是让用户和页面向前移动,同时在后台发送电子邮件。我有一种感觉,我可能还是做错了什么。因此,如果有人遇到这种情况,他们可能想自己尝试一下。
这是我如何100%异步发送电子邮件的完整解决方案,以及ELMAH.MVC错误日志记录。我决定使用示例2的扩展版本:
public void SendThat(MailMessage message)
{
AsyncMethodCaller caller = new AsyncMethodCaller(SendMailInSeperateThread);
AsyncCallback callbackHandler = new AsyncCallback(AsyncCallback);
caller.BeginInvoke(message, callbackHandler, null);
}
private delegate void AsyncMethodCaller(MailMessage message);
private void SendMailInSeperateThread(MailMessage message)
{
try
{
SmtpClient client = new SmtpClient();
client.Timeout = 20000; // 20 second timeout... why more?
client.Send(message);
client.Dispose();
message.Dispose();
// If you have a flag checking to see if an email was sent, set it here
// Pass more parameters in the delegate if you need to...
}
catch (Exception e)
{
// This is very necessary to catch errors since we are in
// a different context & thread
Elmah.ErrorLog.GetDefault(null).Log(new Error(e));
}
}
private void AsyncCallback(IAsyncResult ar)
{
try
{
AsyncResult result = (AsyncResult)ar;
AsyncMethodCaller caller = (AsyncMethodCaller)result.AsyncDelegate;
caller.EndInvoke(ar);
}
catch (Exception e)
{
Elmah.ErrorLog.GetDefault(null).Log(new Error(e));
Elmah.ErrorLog.GetDefault(null).Log(new Error(new Exception("Emailer - This hacky asynccallback thing is puking, serves you right.")));
}
}
发布于 2014-03-18 14:02:12
从.NET 4.5开始,SmtpClient实现了异步可等待方法SendMailAsync
。因此,异步发送电子邮件的步骤如下:
public async Task SendEmail(string toEmailAddress, string emailSubject, string emailMessage)
{
var message = new MailMessage();
message.To.Add(toEmailAddress);
message.Subject = emailSubject;
message.Body = emailMessage;
using (var smtpClient = new SmtpClient())
{
await smtpClient.SendMailAsync(message);
}
}
发布于 2012-01-06 02:22:12
如果你正在使用.Net的SmtpClient和MailMessage类,你应该注意一些事情。首先,预计发送时会出现错误,因此捕获并处理它们。其次,在.Net 4中,这些类有一些变化,现在都实现了IDisposable (MailMessage从3.5开始,SmtpClient在4.0中是新的)。因此,您创建的SmtpClient和MailMessage应该使用块进行包装或显式处理。这是一些人没有意识到的突破性变化。
有关使用异步发送时的处理的更多信息,请参阅此SO问题:
What are best practices for using SmtpClient, SendAsync and Dispose under .NET 4.0
https://stackoverflow.com/questions/8747483
复制相似问题