none
SmtpClient.SendAsync()函数为什么还是阻塞调用线程? RRS feed

  • 问题

  • 最近做一个asp.net项目,msdn上解释这个函数是用来进行异步调用的,但是在项目中实验调用依旧是同步的,只有回调函数完成后才执行SmtpClient.SendAsync()后面的语句。

    难道这是个Bug么?

    2013年8月23日 6:09

答案

  • 不我用异步的发送邮件就是因为邮件发送太慢,大概要20s的样子,所以才想用异步发送。在你那里难道这个函数不会阻塞线程么?

    我测试过了,现象同你描述的一致,但是原因并不是 SmtpClient.SendAsync() 是阻塞的问题。

    SmtpClient.SendAsync() 调用后会立即返回,这也符合 async 的描述,但是页面的输出却要等到此异步操作完成,

    我简单的看了下,问题在于调用 client_SendCompleted 的线程仍然是 asp.net 线程,其 ExecuteContext 是 {System.Web.AspNetSynchronizationContext},也就是 Asp.Net 做了同步。

    解决的办法,一是实现异步页,如果你期望能拿到结果后显示页面的话;另一种就是用 ThreadPool.QueueUserWorkItem(new WaitCallback(sendMailCallback)); 此时页面会立即刷新,但是不知道发送结果。

    2013年8月23日 7:35

全部回复

  • 是吗?你能把页面代码贴出来吗?

    如果如你所说“在回掉函数完成后才执行SmtpClient.SendAsync()后面的语句”的话,那么是否在SmtpClient.SendAsync()后有等待的语句块。

    • 已编辑 Skyseer 2013年8月23日 6:21
    2013年8月23日 6:18
  •  private string sendMail(string caseNumber, string caseOwner)
            {
                MailMessage message = new MailMessage();
                MailAddress from = new MailAddress("");
                message.From = from;

                message.To.Add(new MailAddress(""));
                message.Subject = "";
                string body = "";
                body += "Hi all,      \n\n";
             
                message.Body = body;
                string result = "";


                SmtpClient client = new SmtpClient("");
                client.SendCompleted += new SendCompletedEventHandler(client_SendCompleted);

                client.SendAsync(message, "0");
                Response.Write("目测这是vs里面的BUG");
             
                return result;
            }

    void client_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
            {
                string result = "";
                if (e.Error != null)
                {
                    result = "Sent mail to xx fialed with error: " + e.UserState.ToString();
                }
                else
                {
                    result = "An e-mail has been sent to xx to handle your case!";
                }

                Page.ClientScript.RegisterClientScriptBlock(Page.GetType(), "message", " <script>alert('" + result + "'); </script>");
            }

    2013年8月23日 6:21
  • 是否会发送的过程太快导致的错觉,我建议你在 client_SendCompleted 中加入如下代码观察下结果:

    Thread.Sleep(3000);

    2013年8月23日 6:32
  • 不我用异步的发送邮件就是因为邮件发送太慢,大概要20s的样子,所以才想用异步发送。在你那里难道这个函数不会阻塞线程么?
    2013年8月23日 6:37
  • 你若能告诉我一个 smtp 服务器,我或许可以测试下。我翻了下源码,没发现错误。
    2013年8月23日 7:00
  • 不我用异步的发送邮件就是因为邮件发送太慢,大概要20s的样子,所以才想用异步发送。在你那里难道这个函数不会阻塞线程么?

    我测试过了,现象同你描述的一致,但是原因并不是 SmtpClient.SendAsync() 是阻塞的问题。

    SmtpClient.SendAsync() 调用后会立即返回,这也符合 async 的描述,但是页面的输出却要等到此异步操作完成,

    我简单的看了下,问题在于调用 client_SendCompleted 的线程仍然是 asp.net 线程,其 ExecuteContext 是 {System.Web.AspNetSynchronizationContext},也就是 Asp.Net 做了同步。

    解决的办法,一是实现异步页,如果你期望能拿到结果后显示页面的话;另一种就是用 ThreadPool.QueueUserWorkItem(new WaitCallback(sendMailCallback)); 此时页面会立即刷新,但是不知道发送结果。

    2013年8月23日 7:35