2013-07-25 163 views
7

我被困在異步死鎖,我找不出正確的語法來解決它。我看過幾種不同的解決方案,但似乎無法弄清楚是什麼導致了這個問題。異步等待處理程序死鎖

我使用Parse作爲後端,並嘗試使用處理程序寫入表。我的處理程序看起來像:

public class VisitorSignupHandler : IHttpHandler 
{ 
    public void ProcessRequest(HttpContext context) 
    { 
     //Get the user's name and email address 
     var UserFullName = context.Request.QueryString["name"].UrlDecode(); 
     var UserEmailAddress = context.Request.QueryString["email"].UrlDecode(); 

     //Save the user's information 
     var TaskToken = UserSignup.SaveUserSignup(UserFullName, UserEmailAddress); 
     TaskToken.Wait(); 
     .... 

    } 

    public bool IsReusable { get { return false; } } 
} 

然後,它呼喚我的中間層:

public static class UserSignup 
{ 
    public static async Task SaveUserSignup(string fullName, string emailAddress) 
    { 
     //Initialize the Parse client with the Application ID and the Windows key 
     ParseClient.Initialize(AppID, Key); 

     //Create the object 
     var UserObject = new ParseObject("UserSignup") 
          { 
           {"UserFullName", fullName}, 
           {"UserEmailAddress", emailAddress} 
          }; 

     //Commit the object 
     await UserObject.SaveAsync(); 
    } 
} 

儘管這似乎是陷入在Wait()。我的印象是,Wait()只是等待任務完成,然後返回到正常操作。這是不正確的?

回答

13

您遇到了一個常見的死鎖問題,我描述了on my blogin a recent MSDN article

簡而言之,默認情況下,await將在捕獲的「上下文」內恢復其async方法,並且在ASP.NET上,一次只允許一個線程進入該「上下文」。因此,當您撥打Wait時,您將阻止該環境中的線程,並且在準備好恢復async方法時,await無法進入該環境。因此,上下文中的線程被阻止在Wait(等待async方法完成),並且async方法被阻止,等待上下文被釋放......死鎖。

要解決這個問題,你應該「一路異步」。在這種情況下,使用HttpTaskAsyncHandler代替IHttpHandler

public class VisitorSignupHandler : HttpTaskAsyncHandler 
{ 
    public override async Task ProcessRequestAsync(HttpContext context) 
    { 
    //Get the user's name and email address 
    var UserFullName = context.Request.QueryString["name"].UrlDecode(); 
    var UserEmailAddress = context.Request.QueryString["email"].UrlDecode(); 

    //Save the user's information 
    var TaskToken = UserSignup.SaveUserSignup(UserFullName, UserEmailAddress); 
    await TaskToken; 
    .... 

    } 
} 
+0

謝謝!我在發佈之前先閱讀您的博客,但無法完全弄清楚語法。這很好。欣賞它。 –

+1

不客氣!附:給[TAP文檔](http://msdn.microsoft.com/en-us/library/hh873175.aspx)一個很好的閱讀;這裏有一些'async'約定,特別是將'SaveUserSignup'重命名爲'SaveUserSignupAsync'。 –

1

你的問題是,你是混合式同步和異步代碼。這可以完成,但很棘手。你最好的選擇是讓你的http處理器異步:

public class VisitorSignupHandler : HttpTaskAsyncHandler 
    { 
     public override async Task ProcessRequestAsync(HttpContext context) 
     { 
      //Get the user's name and email address 
      var UserFullName = context.Request.QueryString["name"].UrlDecode(); 
      var UserEmailAddress = context.Request.QueryString["email"].UrlDecode(); 

      //Save the user's information 
      await UserSignup.SaveUserSignup(UserFullName, UserEmailAddress); 
.. 

     } 
    }