2015-08-29 71 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); 
} 
相關問題