c# - WebApi Controller - 发送邮件异步

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

我有一个 WebApi Controller ,其中一个部分正在向一组用户发送电子邮件。

[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); 似乎不是异步的。它在那里停了一会儿。

有什么想法吗?

谢谢

最佳答案

async 的作用是让您的服务器在您的慢速方法异步执行时运行其他线程。也就是说,当您 await 异步方法时,服务器会执行另一个线程,直到 async 方法执行完毕,然后继续运行调用异步方法的线程。 Controller 中的异步操作在幕后以完全相同的方式处理。因此,在 async 电子邮件发送完成之前,您的 async 操作不会响应浏览器。

注意:例如,如果与电子邮件服务器或 DNS 解析存在连接问题,您通常会在 30 秒后超时,因此您的线程将在 30 秒内休眠,并且仅然后会将答案发送给浏览器

如果你想快速将响应返回给你的浏览器,你需要实现一个不同的想法,即启动一个发送电子邮件的新线程,但不要等待它完成,这样你的线程就一直运行并立即将 asnwer 返回给浏览器。这就是众所周知的即发即弃。要理解我在说什么,请看这个:Fire and forget approach .然后仔细阅读其他内容:Fire and Forget (Asynch) ASP.NET Method Call .考虑到 MVC 本身是线程化的,您在使用即发即弃方法时需要考虑到这一点。

很明显,一劳永逸, Controller 将无法在电子邮件发送期间检测到错误,因为新线程在主线程已经完成时自行运行。所以你必须实现一些东西来至少记录可能的错误,理想情况下让用户现在知道发生了什么(例如,他可以稍后看到哪些报告)。请看这个:ASP.NET Exception Handling in background threads

关于c# - WebApi Controller - 发送邮件异步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30277061/

相关文章:

c# - Entity Framework 核心 1.0.0 : Eager loading with Where-clause

c# - 如何使用 webclient 异步下载多个文件,但一次下载一个文件?

javascript - 仅在桌面版本上使 js 代码异步

asynchronous - 如何借用/避免在 tokio::spawn(async

c# - 将文件从一个文件夹移动到另一个 C#

c# - 防止点击事件传播到父元素 xaml

java - 从 whatsapp 获取邮件 Intent

php - 使用 PHP 代码发送电子邮件

email - 控制 cron 作业复杂性的方法或软件系统?

c# - 如果一个字段为空,我如何用 Linq 替换一个值?