WebApi控制器 - 发送邮件异步

时间:2015-05-16 14:48:25

标签: c# email asynchronous asp.net-web-api sendgrid

我有一个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 个答案:

答案 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