错误:异步操作仍处于挂起状态时,异步模块或处理程序已完成

我有一个Controller Action方法来保存用户详细信息,如下所示。

public async Task SaveUser(ViewModel.VM_CreateUser user) { var result = await _user.Save(userDetails); return Json(new { Success = String.IsNullOrEmpty(result) }); } 

到目前为止,上述4行function没有问题。

 public async Task SaveUser(ViewModel.VM_CreateUser user) { var result = await _user.Save(userDetails); new MailController().CreateUser(user.userDetails); //<==This is problem line of code. } 

以下是我的邮件控制器。

 public class MailController : MailerBase { public void CreateUser(ViewModel.VM_User user) { To.Add(user.EmailAddress); From = System.Configuration.ConfigurationManager.AppSettings["emailSender"]; Subject = "Hi"; Email("CreateUser", user).DeliverAsync(); } } 

在上面的代码中,我在执行电子邮件发送代码时遇到问题。 我收到以下错误消息。

在异步操作仍处于挂起状态时完成异步模块或处理程序

请建议纠正措施!!

DeliverAsync是否返回任务? 如果是的话,试试这个。

 public class MailController : MailerBase { public async Task CreateUserAsync(ViewModel.VM_User user) { To.Add(user.EmailAddress); From = System.Configuration.ConfigurationManager.AppSettings["emailSender"]; Subject = "Hi"; await (Email("CreateUser", user).DeliverAsync()); } } 

然后在您的控制器中,等待CreateUserAsync返回的任务。

  public async Task SaveUser(ViewModel.VM_CreateUser user) { var result = await _user.Save(userDetails); await (new MailController().CreateUserAsync(user.userDetails)); return Json(new { Success = String.IsNullOrEmpty(result) }); } 

注意:如果你的目标是让电子邮件发送背景并忘记操作,那就不是了。

这是因为async方法跟踪它们的完成,甚至是async void 。 他们通过在启动时注册SynchronizationContext并在返回时标记操作完成来完成此操作。 ASP.NET跟踪所有创建的操作,并要求在操作返回之前完成所有操作,否则它会向HTTP客户端返回错误。 如果需要运行“fire and forget”方法,则必须手动避免在ASP.NET SynchronizationContext上启动它。 例如, await Task.Run(() => CallFireAndForget())await等待同步部分运行。这是有效的,因为该方法是async void 。要触发async Task即发射,忘记,你必须明确地避免将Task返回到Task.Run()如下所示: await Task.Run(() => { CallFireAndForgetAsync(); }) )。

获取相同错误消息的另一种方法应该是在异步操作中写入:

 // BAD CODE, DEMONSTRATION ONLY! AsyncOperationManager.CreateOperation(); 

如果使用AsyncOperation API,则必须确保在允许action方法返回之前调用AsyncOperation.OperationCompleted()

在您的情况下,如果邮件发送确实是一个即发即弃的任务,您可以在将其签名更改为async Task CreateUserAsync(ViewModel.VM_User user)后,在CreateUser内部执行以下async Task CreateUserAsync(ViewModel.VM_User user)

 await Task.Run(() => Email("CreateUser", user).DeliverAsync()); 

在你的行动中:

 await new MailController().CreateUserAsync(user.userDetails); 

理想情况下,你不会使用Task.Run()的东西。 相反,您可以暂时替换当前的SynchronizationContext

 var originalSynchronizationContext = SynchronizationContext.Current; try { SynchronizationContext.SetSynchronizationContext(null); new MailController().CreateUser(user.userDetails); } finally { SynchronizationContext.SetSynchronizationContext(originalSynchronizationContext); }