BackgroundWorker在发生处理异常时停止

时间:2014-01-02 16:22:40

标签: c# email smtp backgroundworker

在WinForms应用程序中,我运行了几个BackgroundWorkers来发送批量电子邮件。 (不,这不是垃圾邮件,而是公司电子邮件)。

发送电子邮件时,有时会发生 SmtpException('发送邮件失败')。这个SmtpException抛出try-catch并写入日志中。但是,当特别发生此异常时,将异常写入日志并继续,大约需要5分钟,之后每封电子邮件都会因相同的异常而失败(并且处理每封失败的电子邮件大约需要5分钟)。 / p>

从我的研究中我已经读到,当在调试模式下抛出未处理的异常时,BackgroundWorker会停止。但是,我使用调试和发布配置运行项目,行为是相同的。 即使在调试模式下,BackgroundWorker也会停止很长时间,而调试器不会弹出任何异常消息。

另请注意,此错误很难重现,因为第一次发送消息“发送邮件失败”的SmtpException会在300-800封电子邮件之间发送,看似随机点。

对于日志记录我只是使用来自System.Diagnostics的Trace,所以我认为这不是问题所在。

编辑:我还应该补充一点,在极少数情况下,当SmtpException出现“发送邮件失败”消息时,BackgroundWorker会完全停止浏览电子邮件。我让它挂在那里只是为了它的地狱和1小时后它继续发送电子邮件,没有发生任何事情。

以下是DoWork的代码:

private void sender_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    SalaryEmail[] emails = e.Argument as SalaryEmail[];

    SmtpClient smtpClient = new SmtpClient("smtp.office365.com", 587);
    smtpClient.EnableSsl = true;
    smtpClient.Credentials = new NetworkCredential(SalaryEmail.SmtpCredentials.User, SalaryEmail.SmtpCredentials.Password);

    foreach (SalaryEmail email in emails)
    {
        if (worker.CancellationPending == true)
        {
            e.Cancel = true;
            break;
        }
        else
        {
            // Sending and database operations here
            email.Send(ref smtpClient);

            // In this case I only report progress to a progressBar with previously set steps, so the number is irrelevant
            worker.ReportProgress(0);
        }
    }

    smtpClient.Dispose();
}

这是SalaryEmail.Send:

public bool Send(ref SmtpClient smtpClient)
{
    bool sent = false;

    for (int i = 0; i < MAX_ATTEMPTS; i++)
    {
        try
        {
            // Mail is a System.Net.Mail.MailMessage non-static property created and configured previously within the class
            smtpClient.Send(Mail); 
            sent = true;
        }
        catch (SmtpException smtpEx)
        {
            Trace.WriteLine(DateTime.Now + " Intento " + i + " SmtpException: " + smtpEx.Message);
        }
        catch (Exception ex)
        {
            Trace.WriteLine(DateTime.Now + " Intento " + i + " Error al enviar: " + ex.Message);
        }

        // Update database
        if (sent)
        {
            try
            {
                Database.MarkAsSent(Qna, RFC);
            }
            catch (Exception e)
            {
                Trace.WriteLine(DateTime.Now + " Error al marcar enviados" + e.Message);
            }

            break;
        }
    }

    return sent;
}

例外细节:

A first chance exception of type 'System.Net.Mail.SmtpException' occurred in System.dll
02/01/2014 12:57:25 Intento 0 SmtpException: System.Net.Mail.SmtpException: Error al enviar correo. ---> System.Net.WebException: Se excedió el tiempo de espera de la operación.
   en System.Net.ConnectionPool.Get(Object owningObject, Int32 result, Boolean& continueLoop, WaitHandle[]& waitHandles)
   en System.Net.ConnectionPool.GetConnection(Object owningObject, GeneralAsyncDelegate asyncCallback, Int32 creationTimeout)
   en System.Net.Mail.SmtpConnection.GetConnection(ServicePoint servicePoint)
   en System.Net.Mail.SmtpTransport.GetConnection(ServicePoint servicePoint)
   en System.Net.Mail.SmtpClient.GetConnection()
   en System.Net.Mail.SmtpClient.Send(MailMessage message)
   --- Fin del seguimiento de la pila de la excepción interna ---
   en System.Net.Mail.SmtpClient.Send(MailMessage message)
   en MailingClient.SalaryEmail.Send(SmtpClient& smtpClient) en C:\Users\mrivera\Documents\Visual Studio 2010\Projects\PayrollMailing\MailingClient\SalaryEmail.cs:línea 62

跟踪:

02/01/2014 1:44:56 Sending email...
02/01/2014 1:45:01 Updating database...
02/01/2014 1:45:01 Sending email...
02/01/2014 1:45:06 Updating database...
02/01/2014 1:45:07 Sending email...
02/01/2014 1:45:11 Updating database...
02/01/2014 1:45:11 Sending email...
<exception posted above here>
The thread '<No Name>' (0x1890) has exited with code 0 (0x0).
The thread '<No Name>' (0x444) has exited with code 0 (0x0).
The thread '<No Name>' (0xb90) has exited with code 0 (0x0).
The thread '<No Name>' (0x1b00) has exited with code 0 (0x0).
The thread '<No Name>' (0x2754) has exited with code 0 (0x0).
The thread '<No Name>' (0x978) has exited with code 0 (0x0).
The thread '<No Name>' (0x1a68) has exited with code 0 (0x0).
The thread '<No Name>' (0x18b0) has exited with code 0 (0x0).
The thread '<No Name>' (0x1b68) has exited with code 0 (0x0).
The thread '<No Name>' (0x24fc) has exited with code 0 (0x0).
The thread '<No Name>' (0x18c0) has exited with code 0 (0x0).
The thread '<No Name>' (0xa1c) has exited with code 0 (0x0).

1 个答案:

答案 0 :(得分:0)

BackgroundWorker因异常而停止,并且可以在worker的Completed事件中找到该异常。你可以检查它的堆栈跟踪。为了阻止因异常而导致的进程抢占,你应该在try catch中使用DoWork

  

如果操作引发了代码无法处理的异常,   BackgroundWorker捕获异常并将其传递给   RunWorkerCompleted事件处理程序,它作为错误公开   System.ComponentModel.RunWorkerCompletedEventArgs的属性。如果你   在Visual Studio调试器下运行,调试器将中断   在DoWork事件处理程序中未处理的异常的位置   被提出来了。

注册RunWorkerCompleted事件以获取详细的异常跟踪

public void MyProg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
    if (e.Error != null) {
        // You have an exception, which you can examine through the e.Error property.
        //display your exception details here
    } else {
        // No exception in DoWork.
       //happy ending
        }
    }
}

关于发送批量电子邮件,我建议使用SendAsync而不是SmtpClient的Send方法。另外由于某种原因,您的smtp可能拒绝接收来自您的应用程序的电子邮件消息,因此尝试封装您的每个电子邮件发送逻辑并尝试调试您发现异常的特定电子邮件并尝试使用某个阈值降低邮件/秒(每秒30封邮件) )避免在SMTP服务器上过度活跃。