我有一个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);
似乎并不是异步。它停在那里一段时间。
有什么想法吗?
由于
答案 0 :(得分:9)
async
的作用是允许服务器在异步执行慢速方法时运行其他线程。即,当您await
为异步方法时,服务器执行不同的线程,直到async
方法完成执行,然后继续运行调用异步方法的线程。控制器中的异步操作在幕后完全以相同的方式处理。因此,在async
电子邮件发送完成后,您的async
操作对浏览器的响应才会发生。
注意:例如,如果电子邮件服务器存在连接问题或DNS解析,您通常会在30秒后获得超时,因此您的线程将在30秒内睡眠,并且仅然后将答案发送到浏览器
如果你想快速将响应返回给你的浏览器,你需要实现一个不同的想法,即启动一个发送电子邮件的新线程,但不要等待它完成,以便你的线程保持运行并立即将asnwer返回给浏览器。这被称为 fire and forget 。要了解我所说的内容,请参阅:Fire and forget approach。然后仔细阅读另一个:Fire and Forget (Asynch) ASP.NET Method Call。考虑到MVC本身是线程化的,你需要在使用fire and forget方法时考虑它。
在火灾中忘记,忘记了,控制器将无法在电子邮件发送过程中检测到错误,因为新线程在主线程已经完成时自行运行。因此,您必须实现某些内容以至少记录可能的错误,并且理想情况下让用户现在发生了什么(例如,哪些报告他稍后可以看到)。请看这个:ASP.NET Exception Handling in background threads