ASP.NET Web API异步任务,发送邮件

3
我的应用程序存在巨大的性能问题。我发现问题出在发送电子邮件上。当电子邮件正在发送过程中,我如何修复这个问题使方法RegisterUser返回? 我已经尝试使用启动线程来运行SendEmailConfirm方法,但这导致了SendEmailConfirm中的ObjectDisposedException异常。
public async Task<IdentityResult> RegisterUser(AccountViewModels.RegisterViewModel userModel)
{
    var result = await _userManager.CreateAsync(user, userModel.Password);
    this.SendEmailConfirm(userModel.Email);

    return result;
}

public async void SendEmailConfirm(string mail)
{

    string subject = "Please confirm your Email for Chronicus";
    string body = "Hello"
    string email = user.Email;

    _messageService.SendMail(mail, subject, body);

}

public void SendMail(string receiver, string subject, string body)
    {
        this._msg = new MailMessage(UserName, receiver);
        this._msg.From = new MailAddress(UserName, Name);
        this._msg.Subject = subject;
        this._msg.Body = body;
        this._msg.IsBodyHtml = true;
        this._smtpClient.Send(_msg);
    }

编辑:在问题中添加了SendMail方法


_messageService.SendMail的签名是什么?它是异步方法吗?它返回什么? - Yacoub Massad
我编辑了我的问题并添加了这个方法。 - davidrue
  1. 你不应该在调用SendEmailConfirm时使用await吗?
  2. 你是如何/何时实例化_messageService的?
  3. SendMail()来自于不同的类吗?请澄清。
- kayess
如果_messageService正在同步发送邮件,那就是你的问题。我会回到_messageService的实现中,并添加一个可等待的异步方法,该方法使用SmtpClient.SendMailAsync,从而允许IO以正确的异步方式发生。 - spender
  1. 我理解 "await" 的方式是,如果我 "await" "SendEmailConfirm",调用该方法的方法将不会继续执行,直到 "SendEmailConfirm" 被执行。
  2. 我在构造函数中初始化了 _messageService。
  3. SendMail 在 MailMessageService 类中。_messageService 是该类的一个对象。
- davidrue
@spender 我会尝试这个。 - davidrue
1个回答

4

你需要使用SmtpClient类的SendMailAsync方法。

此外,对于返回值为空的异步方法,应该返回Task

以下是你的代码示例:

public async Task<IdentityResult> RegisterUser(AccountViewModels.RegisterViewModel userModel)
{
    var result = await _userManager.CreateAsync(user, userModel.Password);
    await this.SendEmailConfirm(userModel.Email);

    return result;
}

public Task SendEmailConfirm(string mail)
{
    string subject = "Please confirm your Email for Chronicus";
    string body = "Hello"
    string email = user.Email;

    return _messageService.SendMail(mail, subject, body);
}

这是SendMail的样子:

public Task SendMail(string receiver, string subject, string body)
{
    this._msg = new MailMessage(UserName, receiver);
    this._msg.From = new MailAddress(UserName, Name);
    this._msg.Subject = subject;
    this._msg.Body = body;
    this._msg.IsBodyHtml = true;

    return this._smtpClient.SendMailAsync(_msg);
}

1
“SendMail” 不需要是 “async”。它可以只返回 “this._smtpClient.SendMailAsync”,以避免创建状态机。同时,按照 TAP 约定,“SendMail” 应该重命名为 “SendMailAsync”。 - Sriram Sakthivel
1
@SriramSakthivel,我更新了答案。我同意您关于命名约定的看法。我保留方法名称,因为我不想让OP感到困惑。 - Yacoub Massad
我尝试了这个解决方案。但是,“RegisterUser”仍然会等待电子邮件发送完成后才返回结果。 - davidrue
@davidrue,它是异步等待的。你想要发射并忘记吗?如果发送电子邮件时出现异常,你会如何处理? - Yacoub Massad
2
如果您需要“发射并忘记”,那么您需要让消息服务在Web API请求的生命周期之外保持活动状态。您可以拥有一个具有单例生命周期样式的消息服务单个实例。这种服务应该为您处理错误。由于请求可能在发送电子邮件之前已完成,因此此类错误无法显示在Web请求中。但是,例如,它可以记录错误。 - Yacoub Massad
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接