c# - 在 ASP.NET 中异步发送电子邮件的正确方法...(我做对了吗?)

标签 c# asp.net email asynchronous

当用户在我的网站上注册时,我不明白为什么我需要让他“等待”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 被重新启动所以网站上的任何人都有他们的 session 被删除了。完全不能接受的结果!

我的下一个想法是对异步委托(delegate)进行一些研究。这似乎工作得更好,因为异常是在异步委托(delegate)中处理的(与上面的线程示例不同)。但是,我担心我是否做错了或者可能导致内存泄漏。

这是我正在做的:

Emailer mailer = new Emailer();
AsyncMethodCaller caller = new AsyncMethodCaller(mailer.SendMailInSeperateThread);
caller.BeginInvoke(message, email.EmailId, null, null);
// Never EndInvoke... 

我这样做对吗?

最佳答案

我在这里赞成很多好的建议...例如确保记住使用 IDisposable(我完全不知道)。我还意识到在另一个线程中手动捕获错误是多么重要,因为没有上下文——我一直在研究一个理论,我应该让 ELMAH 处理所有事情。此外,进一步探索让我意识到我也忘记了在 mailmessage 上使用 IDisposable。

作为对 Richard 的回应,虽然我看到线程解决方案可以工作(如我的第一个示例中所建议的那样),但只要我捕捉到错误...如果 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.")));
    }
}

关于c# - 在 ASP.NET 中异步发送电子邮件的正确方法...(我做对了吗?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8747483/

相关文章:

.net - powershell 或 net 发送带有身份验证的电子邮件

java - 尝试使用 SMTP Appender 时出现 Log4J2 Factory 错误

c# - 如何将包含 "c:\test.zip"的字符串替换为 @"c:\test.zip"

c# - 通过静态对象的静态属性访问 asp.net session 变量是否安全?

asp.net - Linq 查询在 LinqPad 中工作但在 VS 中不起作用

asp.net - 如何获取插入表的最后一行的主键

c# - 扩展 Wpf Treeview 以支持排序

c# - Entity Framework 6.1.1 DbJoinExpression 获取所有左列

asp.net - 在 WCF 应用程序中使用 HostingEnvironment.QueueBackgroundWorkItem

ruby-on-rails-3 - Rails3 和 Heroku : Sending Emails?