Ral*_*h N 20 c# asp.net email asynchronous
当用户在我的网站上注册时,我不明白为什么我需要让他"等待"smtp通过才能获得激活电子邮件.
我决定以异步方式启动此代码,这是一次冒险.
让我们想象一下我有一个方法,例如:
private void SendTheMail() { // Stuff }
Run Code Online (Sandbox Code Playgroud)
我的第一个虽然是线程.我这样做了:
Emailer mailer = new Emailer();
Thread emailThread = new Thread(() => mailer.SendTheMail());
emailThread.Start();
Run Code Online (Sandbox Code Playgroud)
这工作......直到我决定测试它的错误处理能力.我故意破坏了我的web.config中的SMTP服务器地址并尝试了它.可怕的结果是IIS基本上BARFED与w3wp.exe上的未处理的异常错误(这是一个Windows错误!多么极端......)ELMAH(我的错误记录器)没有捕获它并且IIS重新启动所以网站上的任何人都有他们的会话被删除了.完全不可接受的结果!
我的下一个想法是,对异步代表进行一些研究.这看起来效果更好,因为在异步委托中处理异常(与上面的线程示例不同).但是,我担心如果我做错了或者我可能导致内存泄漏.
这是我正在做的事情:
Emailer mailer = new Emailer();
AsyncMethodCaller caller = new AsyncMethodCaller(mailer.SendMailInSeperateThread);
caller.BeginInvoke(message, email.EmailId, null, null);
// Never EndInvoke...
Run Code Online (Sandbox Code Playgroud)
我这样做了吗?
Ral*_*h N 25
我在这里投了很多好建议......比如确保记得使用IDisposable(我完全不知道).我也意识到在另一个线程中手动捕获错误是多么重要,因为没有上下文 - 我一直在研究一个理论,我应该让ELMAH处理所有事情.此外,进一步的探索让我意识到我忘记了在邮件消息上使用IDisposable.
在回应理查德的时候,虽然我看到线程解决方案可以工作(正如我的第一个例子所示),只要我抓住了错误......但是如果那个错误不是,那么IIS完全爆炸的事实仍然是可怕的.抓住了.这告诉我ASP.NET/IIS从来没有意味着你这样做...这就是为什么我倾向于继续使用.BeginInvoke/delegates而不是因为当出现问题时它不会弄乱IIS并且似乎在ASP.NET中更受欢迎.
为了回应ASawyer,我完全惊讶于SMTP客户端内置了一个.SendAsync.我玩了一段时间的解决方案,但它似乎并不适合我.虽然我可以跳过执行SendAsync的代码客户端,但页面仍然"等待",直到SendCompleted事件完成.我的目标是让用户和页面向前移动,同时在后台发送电子邮件.我有一种感觉,我可能仍然会做错事......所以,如果有人来这里,他们可能想自己尝试一下.
这是我完整的解决方案,除了ELMAH.MVC错误记录之外我100%异步发送电子邮件.我决定使用示例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.")));
}
}
Run Code Online (Sandbox Code Playgroud)
从.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);
}
}
Run Code Online (Sandbox Code Playgroud)