为什么发送电子邮件程序会冻结?

时间:2010-11-24 17:34:47

标签: c# .net-3.5 contextswitchdeadlock

我做了一个小程序,我基本上可以通过yahoo smtp服务器发送电子邮件。我的代码:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Net;
using System.Net.Mail;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {

                try
                {

                    MailMessage message = new MailMessage();
                    message.From = new MailAddress("myid@yahoo.com");
                    message.To.Add("anotherid@yahoo.com");
                    message.Subject = "afdasdfasfg";
                    message.Body = "Hgfk4564267862738I";
                    message.IsBodyHtml = true;
                    message.Priority = MailPriority.High;
                    SmtpClient sC = new SmtpClient("smtp.mail.yahoo.com");
                    sC.Port = 587;
                    sC.Credentials = new NetworkCredential("myid", "mypassword");
                    //sC.EnableSsl = true;
                    sC.Send(message);
                    MessageBox .Show ("Mail Send Successfully");

                }
                catch (Exception ex)
                {
                    MessageBox .Show (ex + "Mail Sending Fail's") ;

                }
            }

        }
    }

奇怪的是它在第一周起作用了。我可以毫无问题地发送消息。然后就在昨天,该程序刚刚开始冻结并且没有响应(我没有更改代码)。为什么会这样?我该如何修补我的程序?

编辑:@Andreas Niedermair现在我刚尝试了程序并将其保留了整整一分钟然后出现错误:检测到ContextSwitchDeadlock 消息:CLR无法从COM上下文0x21eb78转换到COM上下文0x21ece8 60秒。拥有目标上下文/公寓的线程很可能是在非抽空等待或处理非常长时间运行的操作而不抽取Windows消息。这种情况通常会对性能产生负面影响,甚至可能导致应用程序变得无响应或内存使用量随时间不断累积。为了避免这个问题,所有单线程单元(STA)线程都应该使用抽取等待原语(例如CoWaitForMultipleHandles)并在长时间运行操作期间定期泵送消息。

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

你的catch到达了吗?

我假设你没有耐心达到Timeout属性的默认值(100秒)...... 你可以减少价值以获得更早的完成。

只要您不使用异步模式,您的UI线程就会被阻止。另一种方法是使用SendAsync方法(msdn-entries中有特定方法的示例实现)。

修改
正如作者提到的可能的端口:是的,它可能是。但你必须阅读specification paper,它告诉我们:

  • SMTP服务器:plus.smtp.mail.yahoo.com
  • 使用SSL
  • 港口:465
  • 使用身份验证
  • 帐户名称/登录名称:您的Yahoo!邮件ID(您的电子邮件地址没有“@ yahoo.com”,例如“testing80”)
  • 电子邮件地址:您的Yahoo!邮件地址(例如,testing80 @yahoo.com)
  • 密码:您的Yahoo!邮件密码
  • [...]尝试通过Yahoo!的SMTP服务器发送电子邮件时将SMTP端口号设置为587。

但即使你符合规范:你应该选择async-pattern:)

修改 提到的异常与COM有关...有点googeling,我发现this

  

可能发生的是你   在表单中有一个COM对象,和   你在UI线程上做的工作。如果   您的UI被处理阻止   对于> 60秒,COM组件可以   抱怨。

修改

否则:你是否在visual studio的例外对话框中改变了什么?那么这可能是你的solutionthis one(有一些基本的解释)......

答案 1 :(得分:0)

根据Andreas Niedermair编辑,问题是你阻止主线程超过60秒。最好的办法是将此操作放在后台线程上。

using System;
using System.ComponentModel;
using System.Net;
using System.Net.Mail;
using System.Windows.Forms;

namespace Sandbox_Form
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            bw = new BackgroundWorker();
            bw.DoWork +=new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if(e.Error != null)
                MessageBox.Show(e.Error.ToString() + "Mail Sending Fail's") ;
            else
                MessageBox.Show("Mail Send Successfully");
        }

        BackgroundWorker bw;

        void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            using(MailMessage message = new MailMessage())
            {
                message.From = new MailAddress("myid@yahoo.com");
                message.To.Add("anotherid@yahoo.com");
                message.Subject = "afdasdfasfg";
                message.Body = "Hgfk4564267862738I";
                message.IsBodyHtml = true;
                message.Priority = MailPriority.High;
                using(SmtpClient sC = new SmtpClient("smtp.mail.yahoo.com"))
                {
                    sC.Port = 587;
                    sC.Credentials = new NetworkCredential("myid", "mypassword");
                    //sC.EnableSsl = true;
                    sC.Send(message);
                }
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            bw.RunWorkerAsync();
        }
    }

}

编辑:

根据Andreas Niedermair的建议,这里是使用异步方法的版本。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    private void button1_Click(object sender, EventArgs e)
    {
        try
        {

            MailMessage message = new MailMessage();
            message.From = new MailAddress("myid@yahoo.com");
            message.To.Add("anotherid@yahoo.com");
            message.Subject = "afdasdfasfg";
            message.Body = "Hgfk4564267862738I";
            message.IsBodyHtml = true;
            message.Priority = MailPriority.High;
            SmtpClient sC = new SmtpClient("smtp.mail.yahoo.com");
            sC.Port = 587;
            sC.Credentials = new NetworkCredential("myid", "mypassword");
            //sC.EnableSsl = true;
            //sC.Send(message);
            sC.SendCompleted += new SendCompletedEventHandler(sC_SendCompleted);
            sC.SendAsync(message, null);

        }
        catch (Exception ex)
        {
            MessageBox.Show(ex + "Mail Sending Fail's");
        }

    }

    void sC_SendCompleted(object sender, AsyncCompletedEventArgs e)
    {
        if(e.Error != null)
            MessageBox.Show(ex + "Mail Sending Fail's");
        else
            MessageBox.Show("Mail Send Successfully");
    }
}