2014-11-22 105 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