2014-11-22 110 views
3

我想知道是否在asp.net c#中以异步方式发送电子邮件。我用下面的代码来发送电子邮件:在ASP.NET C中异步发送电子邮件#

if (checkObavijest.Checked) 
      { 
       List<hsp_Kupci_Newsletter_Result> lista = ServisnaKlasa.KupciNewsletter(); 
       for (int i = 0; i < lista.Count; i++) 
       { 
        MailMessage mail = new MailMessage(); 

        mail.From = new MailAddress("*******"); 
        mail.To.Add(lista[i].Email); 
        mail.Subject = "Subject"; 
        mail.SubjectEncoding = Encoding.UTF8; 
        mail.BodyEncoding = Encoding.UTF8; 
        mail.IsBodyHtml = true; 
        mail.Priority = MailPriority.High; 
        mail.Body = "Some message"; 
        SmtpClient smtpClient = new SmtpClient(); 
        Object state = mail; 
        smtpClient.Credentials = new NetworkCredential("****@gmail.com", "****"); 
        smtpClient.Port = 587; 
        smtpClient.Host = "smtp.gmail.com"; 
        smtpClient.EnableSsl = true; 
        smtpClient.SendCompleted += new SendCompletedEventHandler(smtpClient_SendCompleted); 
        try 
        { 
         smtpClient.SendAsync(mail, state); 
        } 
        catch (Exception ex) 
        { 

        } 
       } 

void smtpClient_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) 
     { 

      MailMessage mail = e.UserState as MailMessage; 

      if (!e.Cancelled && e.Error != null) 
      { 
       string poruka = "Emailovi poslani!"; 
       ClientScript.RegisterStartupScript(this.GetType(), "myalert", "alert('" + poruka + "');", true); 
      } 
     } 

但是,当我打勾的选项用于发送电子邮件,页面负载,如40秒,然后40秒后的电子邮件发送即可。正如你所看到的,我正在从我的数据库中抽出20-30封电子邮件。我认为这是异步发送邮件的正确方式,但显然它不是......我如何将电子邮件发送到另一个线程,以免影响正在使用此页面的用户?有人可以帮我解决这个问题吗?谢谢 !

回答

0

原因是这里提到的MSDN documentation on SmtpClient.SendAsync

调用SendAsync后,必须试图发送使用发送 或SendAsync其他电子邮件消息之前等待的E-mail发送到 完整。

您可以使用ThreadPool通过包装方法调用调用SendAsync。这会让你看起来像一场即忘即忘的场景。

事情是这样的:

public void SendViaThread(System.Net.Mail.MailMessage message) { 
    try { 
     System.Threading.ThreadPool.QueueUserWorkItem(SendViaAsync, message); 
    } catch (Exception ex) { 
     throw; 
    } 
} 

private void SendViaAsync(object stateObject) { 
    System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient(); 
    System.Net.Mail.MmailMessage message = (MmailMessage)stateObject; 
    ... 
    smtp.Credentials = new NetworkCredential("..."); 
    smtp.Port = 587; 
    smtp.Host = "..."; 
    ... 
    smtp.SendCompleted += new SendCompletedEventHandler(smtpClient_SendCompleted); 
    ... 
    smtp.Send(message); 
} 

而且你会叫你的代码SendViaThread(mail)。因此,您的循环现在变为:

for (int i = 0; i < lista.Count; i++) { 
    MailMessage mail = new MailMessage(); 
    mail.From = new MailAddress("..."); 
    mail.To.Add(lista[i].Email); 
    mail.Subject = "..."; 
    ... 
    mail.Body = "..."; 
    SendViaThread(mail); 
} 
+0

我试试看,但为什么你声明sendviathread函数为布尔,为什么不能void# – perkes456 2014-11-22 14:35:14

+0

哦..那是我的代码在我的一个项目中..我正在做更多的工作,并返回一个布尔值来表示问题,你并不真的需要这个,谢谢指出,我会删除那部分。 – Abhitalks 2014-11-22 14:37:59

+0

你能更具体怎么样我把它建成我现有的代码?我真的不知道我应该在这里做什么... – perkes456 2014-11-22 14:52:35

0

如果您不想让主线程等待,请尝试在Task中折腾它。

Task.Factory.StartNew(() => { 
    // do mail stuff here 
}); 

要知道,虽然你每次产卵任务时,它会产生一个新的(或重新使用),您的系统已经做了一个线程。如果您要发送30封电子邮件,您可能会触发线程批处理(该系统也有可编程的上限)。 Task.Factory.StartNew是一个非常简单的方法来做一个即燃即用的过程。

http://msdn.microsoft.com/en-us/library/dd321439%28v=vs.110%29.aspx (在这个例子中,代码也保持的Tasks集合,如果你愿意对它们进行管理,这是很好 - 但在现实中,你只有当你想需要的Task.Factory.StartNew(()=>{位火 - 和 - 忘记了,只是要小心,因为你不希望有孤立线程挂钩你的内存使用情况。

+0

有什么办法一旦他们有发送邮件完了我能处理这些线程的... – perkes456 2014-11-22 15:00:18

+0

不是真的,你可以让系统释放这些任务。一旦完成,他们就完成了。 - 看到这一点: http://blogs.msdn.com/b/pfxteam/archive/2012/03/25/10287435.aspx 顺便说一句,你也可以使用Task.Run(而不是.StartNew) - 看看这一点。如果你想要跟踪你的任务,你可以将它们添加到一个集合中,例如列表中的例子 - 或者在启动时使用''using'将它们包装起来(使用清理本身和本地化)。但我建议让.NET处理清理,而不是担心。 – Jason 2014-11-22 15:05:10

+0

在过去,我已经添加催生线程的集合,这样我可以照看他们的过程中,他们在做什么,并在需要时能够删除它们(多线程是一个有趣的[不]世界去下)。 Task.Run/StartNew可以让你的脚很容易被弄湿,而不用担心线程状态,竞赛状况等等。这里适合你的即忘即战场景。 – Jason 2014-11-22 15:07:04