2015-05-16 49 views
4

我有一個WebApi控制器,其中一個部分發送電子郵件給一組用戶。WebApi控制器 - 發送郵件異步

[HttpPost] 
[Authorize] 
[Route("{id}/Do")] 
public async Task<HttpResponseMessage> Post(int id, Model model) 
... 
    await _emailService.SendAsync(message); 
... 

現在,發送電子郵件(SendGrid)

public override async Task SendAsync(MailMessage message) 
{ 
    var client = 
     new SmtpClient(SendGridServerName, SendGridServerPort) 
     { 
      Port = SendGridServerPort, 
      DeliveryMethod = SmtpDeliveryMethod.Network, 
      UseDefaultCredentials = false 
     }; 

    var credentials = new NetworkCredential(SendGridUserName, SendGridPassword); 

    client.EnableSsl = true; 
    client.Credentials = credentials; 
    message.From = new MailAddress(FromAddress); 

    await client.SendMailAsync(message); 
} 

一切正常,但它是非常慢的方法。我期待它快,但await _emailService.SendAsync(message);似乎不是異步。它在那裏停留了一段時間。

任何想法?

感謝

+1

看看[WebApi異步](http://stackoverflow.com/questions/22814134/multiple-await-async-in-net-webapi)。 「單個請求可能會稍微慢一點」,但是當系統處於負載下時,它會表現得更好。乾淨利落。假設電子郵件客戶端是SmtpServer,你最好用[新線程](http://forums.asp.net/t/1731495.aspx?SmtpClient+SendAsync+doesn+t+do+anything),所以你的行動不是等待這個完成。 – lloyd

+2

我建議使用[SendGrid SDK](https://github.com/sendgrid/sendgrid-csharp)來代替,它們具有使用REST API的'Async'方法。 –

+0

我剛剛更新了原始答案,指出了一些額外的細節,說明您可以如何快速回答用戶。 – JotaBe

回答

8

什麼async不會被允許,同時異步執行的方法速度慢的服務器來運行其他線程。也就是說,當你使用異步方法的await時,服務器執行一個不同的線程,直到async方法完成執行,然後繼續運行調用異步方法的線程。控制器中的異步操作在幕後以完全相同的方式處理。因此,在async電子郵件發送完成之前,您的async操作對瀏覽器的響應將不會發生。

注意:例如,如果電子郵件服務器或DNS解析存在連接問題,您通常會在30秒後超時,因此您的線程將在30秒內睡眠,會將答案發送給瀏覽器

如果您想快速返回瀏覽器的響應,您需要實現一個不同的想法,即啓動發送電子郵件的新線程,但不要等待它完成,以便您的線程繼續運行並立即返回到瀏覽器。這就是所謂的火,忘記。要了解我在說什麼,請參閱:Fire and forget approach。然後仔細閱讀另一本:Fire and Forget (Asynch) ASP.NET Method Call。考慮到MVC本身是線程化的,在使用fire and forget方法時需要考慮到它。

在火災中遺忘並忘記,控制器將無法檢測到電子郵件發送過程中的錯誤,因爲新線程在主線程已經完成時自行運行。所以你必須實現一些東西來至少記錄可能的錯誤,並且最好讓用戶知道發生了什麼事情(例如稍後可以看到的報告)。請看這個:ASP.NET Exception Handling in background threads