2015-08-29 57 views
0

我有一个Controller Action方法来保存下面的用户详细信息。错误:异步模块或处理程序在异步操作仍未完成时完成

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

到目前为止,上述4行函数中没有问题。

public async Task<ActionResult> 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(); 
    } 
} 

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

An asynchronous module or handler completed while an asynchronous operation was still pending

请提出纠正措施!

回答

2

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<ActionResult> SaveUser(ViewModel.VM_CreateUser user) 
    { 
     var result = await _user.Save(userDetails); 
     await (new MailController().CreateUserAsync(user.userDetails)); 
     return Json(new { Success = String.IsNullOrEmpty(result) }); 
    } 

注意:如果您的目标是使发送电子邮件的背景火灾,并忘记操作,这不是。

+0

我收到一个编译错误。 '不能等待空白'。 – Pankaj

+0

如果DeliverAsync()返回void,那么这将无法正常工作。否则,您是否更改CreateUser以返回任务 – labroo

1

这是因为async方法跟踪它们的完成,甚至async void。他们在启动时注册SynchronizationContext,并在返回时标记操作完成。 ASP.NET会跟踪所有已创建的操作,并要求它们在操作返回前全部完成,否则会向HTTP客户端返回错误。如果你需要运行一个“火再遗忘”的方法,你必须手动避免在ASP.NET SynchronizationContext上启动它。例如,await Task.Run(() => CallFireAndForget())await让你等待同步部分运行这工作,因为该方法是async void要发射的async Task为发射后不管,你必须明确地避免返回TaskTask.Run()是这样的:await Task.Run(() => { CallFireAndForgetAsync(); }) )。

另一种方式来获得同样的错误消息露面应该是一个异步动作写这篇文章:

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

如果使用AsyncOperation API,你必须确保你打电话AsyncOperation.OperationCompleted()允许之前操作方法返回。

在你的情况,如果发送的邮件确实是打算成为一个发射后不管的任务,你可以改变它的签名async Task CreateUserAsync(ViewModel.VM_User user)后做的CreateUser内的以下内容:

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); 
} 
相关问题