【问题标题】:Find which Parallel ForEach thread threw exception查找哪个 Parallel ForEach 线程抛出异常
【发布时间】:2017-03-25 05:35:39
【问题描述】:

您好,提前感谢您的建议,

我有一个并行的 For-each 循环,它正在发送大量电子邮件。我想知道的是如何找出哪个线程抛出了 SmtpException。我想知道它无法发送到哪个电子邮件地址。

protected void btnSend_Click(object sender, EventArgs e)
{
    try
    {
        if (Page.IsValid)
        {
            List<string> emailList;
            List<string> invalidList = new List<string> { };
            string[] attachments = { };
            if (rbListType.Items.FindByValue("CSV").Selected)
            {
                emailList = tbEmailTo.Text.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries).ToList();
                int count = 0;
                int total = emailList.Count;
                RadRadialGauge1.Scale.Max = total;
                RadRadialGauge1.Scale.Min = 0;
                //for (int i = 0; i < emailList.Count; i++)
                //{
                //    if (emailList[i].Contains('<'))
                //    {
                //        if (!Mail.IsValidEmailAddress(emailList[i].ToString().Split('<')[1].Replace(">", ""), PortalId))
                //        {
                //            emailList.RemoveAt(i);
                //            invalidList.Add(emailList[i].ToString());
                //        }
                //    }
                //    else
                //    {
                //        if (!Mail.IsValidEmailAddress(emailList[i].ToString(), PortalId))
                //        {
                //            emailList.RemoveAt(i);
                //            invalidList.Add(emailList[i].ToString());
                //        }
                //    }
                //}

                Parallel.ForEach(emailList, email =>
                {
                    Mail.SendMail(tbEmailFrom.Text, email.ToString(), tbEmailCC.Text, tbEmailBC.Text, tbReplyTo.Text, DotNetNuke.Services.Mail.MailPriority.Normal,
                        tbSubject.Text, MailFormat.Html, System.Text.Encoding.UTF8, tbEmailBody.Text, attachments, smtpServer, smtpAuthentication, smtpUsername, smtpPassword, false);
                    Interlocked.Increment(ref count);

                });

                RadRadialGauge1.Pointer.Value = count;

            }
            if (rbListType.Items.FindByValue("Excel").Selected)
            {
                emailList = tbEmailTo.Text.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries).ToList();
                int count = 0;
                int total = emailList.Count;
                RadRadialGauge1.Scale.Max = total;
                RadRadialGauge1.Scale.Min = 0;
                //for (int i = 0; i < emailList.Count; i++)
                //{
                //    if (emailList[i].Contains('<'))
                //    {
                //        if (!Mail.IsValidEmailAddress(emailList[i].ToString().Split('<')[1].Replace(">", ""), PortalId))
                //        {
                //            emailList.RemoveAt(i);
                //            invalidList.Add(emailList[i].ToString());
                //        }
                //    }
                //    else
                //    {
                //        if (!Mail.IsValidEmailAddress(emailList[i].ToString(), PortalId))
                //        {
                //            emailList.RemoveAt(i);
                //            invalidList.Add(emailList[i].ToString());
                //        }
                //    }
                //}


                Parallel.ForEach(emailList, email =>
                {

                    Mail.SendMail(tbEmailFrom.Text, email.ToString(), tbEmailCC.Text, tbEmailBC.Text, tbReplyTo.Text, DotNetNuke.Services.Mail.MailPriority.Normal,
                       tbSubject.Text, MailFormat.Html, System.Text.Encoding.UTF8, tbEmailBody.Text, attachments, smtpServer, smtpAuthentication, smtpUsername, smtpPassword, false);
                    Interlocked.Increment(ref count);

                });
                RadRadialGauge1.Pointer.Value = count;
            }

            throw new SmtpException();
        }
    }
    catch (SmtpException smtp)
    {
        RadRadialGauge1.Pointer.Value = RadRadialGauge1.Pointer.Value - 1;
        var email = smtp.

        Exceptions.LogException(smtp);

    }
    catch (Exception ex)
    {
        Exceptions.LogException(ex);
    }
}

【问题讨论】:

标签: c# exception-handling task-parallel-library dotnetnuke


【解决方案1】:

您可以按照Yuval Itzchakov 的建议将其包装在 try catch 中。然后最后errorList会填满所有无法发送的邮箱。

var errorList = new ConcurrentBag<string>();
Parallel.ForEach(emailList, email =>
{
     try
     {
         Mail.SendMail(tbEmailFrom.Text, email.ToString(), tbEmailCC.Text, tbEmailBC.Text, tbReplyTo.Text, DotNetNuke.Services.Mail.MailPriority.Normal,
         tbSubject.Text, MailFormat.Html, System.Text.Encoding.UTF8, tbEmailBody.Text, attachments, smtpServer, smtpAuthentication, smtpUsername, smtpPassword, false);
         Interlocked.Increment(ref count);  
     }
     catch(SmtpException stmp)
     {
         Exceptions.LogException(smtp);
         errorList.Add(email);
     }   
});
RadRadialGauge1.Pointer.Value = count;

【讨论】:

  • 最好使用 ConcurrentQueue,或者其他线程保存集合。
  • 这将隐藏错误,我会抛出一个新异常,其中包含消息中的电子邮件,并将 SMTP 异常作为内部异常,除非诅咒你可以在捕获错误时处理它走开
  • @MrDywar 您也可以在添加前添加lock (errorList) 以处理并发问题。
  • @MrDywar 同意,ConcurrentBag 就可以了 :)
  • 这行得通 - 但我使用 DotNetNuke 方法发送电子邮件。异常在其源中被捕获。所以我不得不更改代码以使用 System.Net.Mail。
【解决方案2】:

您可以将 Visual Studio 调试器(我假设您正在使用)配置为在抛出异常时立即中断。

打开调试菜单,单击异常项。使用 Find 按钮,搜索 SmtpException,然后单击“Thrown”列中的复选框。当你再次执行你的程序时,它会显示它发生的确切时间,以及调用堆栈、局部变量等。

【讨论】:

  • 这不会帮助最终用户确定电子邮件是否已发送
  • 抱歉,您问题的措辞暗示您想调试问题,而不是通知最终用户。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-18
  • 1970-01-01
  • 2013-08-23
  • 2016-07-28
  • 1970-01-01
  • 1970-01-01
  • 2012-01-11
相关资源
最近更新 更多