2013-09-26 115 views
-2

我仍然試圖包裹我的頭周圍異步,我想知道爲什麼下面的代碼導致死鎖。我的用例是這樣的:我有一個服務接口,試圖抽象服務如何實現。其中一項服務是基於OAuth的網絡服務。服務接口有一個方法Connect(),任何使用該接口的人都必須在使用它之前進行操作。HttpClient等待與異步無效方法PostAsync掛起

在我的客戶端,我創建了具體的服務對象,並在我的視圖構造函數中調用了Connect()(這是一個原型,所以我只是試圖獲得概念證明)。在基於OAuth的服務中,連接調用需要檢索訪問令牌,因此它(嘗試)以異步方式執行此操作。但是,這個調用永遠不會返回,並且應用程序已死鎖(但UI已激活)。我在猜測我搞砸了,試圖在某個地方同步使用我的客戶端,但我不確定它在哪裏。

控制基於

public class MainWindow 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     _webService = new OAuthBasedWebService(); 
     _webService.ShowAuthorizationPage += _webService_ShowAuthorizationPage; // this is defined on the concrete object -- i know, bad design 
     _webService.Connect(); 
    } 
} 

OAuth的Web服務

public class OAuthBasedWebService() 
{ 
    private OAuthWrapper _wrapper; 

    public async void Connect() 
    { 
     var uri = await _wrapper.GetAuthorizationUri(); 
     OnShowAuthorizationPage(uri); 
    } 
} 

internal class OAuthWrapper 
{ 
    public async Task<Uri> GetAuthorizationUri() 
    { 
     var uri = await _consumer.GetAuthorizationUriAsync(); 
     return uri; 
    } 
} 

internal class OAuthConsumer 
{ 
    public async Task<Uri> GetAuthorizationUriAsync() 
    { 
     using (var client = new HttpClient()) 
     { 
      client.BaseAddress = "webservicebaseaddress"; 
      var content = new FormUrlEncodedContent(new [] 
      { 
       CreateParameter("oauth_consumer_key", "consumerkey"), 
       CreateParameter("oauth_consumer_secret", "consumersecret") 
       // etc., etc. 
      }); 

      var response = await client.PostAsync("/method_path", content).ConfigureAwait(false); 
      var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); 

      // parse authorization uri from responseContent 
      return authorizationUri; 
     } 
    } 
} 

我知道設計需要一點的工作,但我試圖找出爲什麼這個被死鎖。我猜這是因爲_webService.Connect()不是異步調用,但我也不能await,因爲它不返回任何東西,程序的其餘部分不依賴它。

+1

我以爲你會發現實際上'Connect'立即返回*,因爲它是一個異步方法。不幸的是,它是一個返回'void'的異步方法,這通常是一個壞主意。您是否在'GetAuthorizationUriAsync'中放置了斷點或診斷信息來確定它實際得到的距離? –

+1

如果UI仍然響應,我不確定「死鎖」是什麼意思。 GetAuthorizationUriAsync是否返回? (順便說一句,我有一些[我的博客上的提示](http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html)避免在構造函數中使用'async void')。 –

+0

'GetAuthorizationUriAsync()'獲取第一個'await'。它永遠不會到達第二個。 – sohum

回答

1

我不知道你爲什麼在這裏使用一個事件,如果問題只是因爲你不能讓構造「異步」,那麼只要將瞬移調用另一個方法:

public class MainWindow 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     Init(); 
    } 

    public async void Init(){ 

     _webService = new OAuthBasedWebService(); 

     Uri uri=await _webService.Connect(); 
     _webService_ShowAuthorizationPage(uri); 
    } 
} 


public class OAuthBasedWebService() 
{ 
    private OAuthWrapper _wrapper; 

    public async Task<Uri> Connect() 
    { 
     return await _wrapper.GetAuthorizationUri(); 

    } 
} 
+0

事件存在,因爲Connect並不總是要求授權頁面。例如,如果用戶已被授權,則不會顯示授權頁面。 – sohum