我正在尝试从Controller异步发送电子邮件,并收到以下错误:

我不想等待发送电子邮件完成操作。


  异步完成的异步模块或处理程序
  操作仍在进行中。


这是我的实现:我也尝试使用void代替async Task

public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    var user = await _userManager.FindByNameAsync(model.Email);
    if (user != null)
    {
        if (!await _userManager.IsEmailConfirmedAsync(user.Id))
        {

            //dont want to await result
            //just send email
            _mailService.SendAccountConfirmationEmailAsync(user);
            ...
        }
        ...
    }
    return View();
}




public async Task SendAccountConfirmationEmailAsync(ApplicationUser user)
{
    dynamic email = GetAccountConfirmationEmailTemplate();

    email.Username = user.Email;
    email.Name = user.UserName;
    email.To = user.Email;
    email.AccountConfirmationUrl = await GetAccountConfirmationUrl(user);

    await _mailService.SendAsync(email);
}


我想念什么?

最佳答案

由于运行时知道知道没有其他待处理的请求时可以循环使用您的appdomain,因此特别不建议您启动不等待的任务,因此该消息是不建议的。

特别是,没有此检查,您将无法保证会发送此电子邮件,因为在您的控制器操作返回后,整个appdomain可能会围绕该任务被删除。

现在,您可能会说丢失电子邮件是可以接受的,但是运行时并不知道这只是一封电子邮件,这很可能是您忘记等待的数据库调用过早了流产了。因此,它只是告诉您这是错误的形式。

相反,您有两种选择:


等待该任务完成,您已经明确表示您不想做
通知运行时您正在执行您特别不想等待的任务,但是请哦,拜托,请不要在任务完成前退出appdomain


这最后一部分是HostingEnvironment.QueueBackgroundWorkItem的用途。

在您的情况下,您可以这样称呼它:

HostingEnvironment.QueueBackgroundWorkItem(ct =>
    _mailService.SendAccountConfirmationEmailAsync(user));


此外,该方法提供了CancellationToken,您应该检查是否有SendAccountConfirmationEmailAsync的重载接受它。如果不是,并且这是您的API,则应考虑添加对此类令牌的支持。

请注意,这种机制并不适合长时间运行的线程或任务,因为还有其他更合适的树可以吠叫,但在这种情况下,它就足够了。

关于c# - 发送电子邮件异步:异步模块或处理程序在异步操作仍处于挂起状态时完成,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44422556/

10-17 01:34