我仍然試圖包裹我的頭周圍異步,我想知道爲什麼下面的代碼導致死鎖。我的用例是這樣的:我有一個服務接口,試圖抽象服務如何實現。其中一項服務是基於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
,因爲它不返回任何東西,程序的其餘部分不依賴它。
我以爲你會發現實際上'Connect'立即返回*,因爲它是一個異步方法。不幸的是,它是一個返回'void'的異步方法,這通常是一個壞主意。您是否在'GetAuthorizationUriAsync'中放置了斷點或診斷信息來確定它實際得到的距離? –
如果UI仍然響應,我不確定「死鎖」是什麼意思。 GetAuthorizationUriAsync是否返回? (順便說一句,我有一些[我的博客上的提示](http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html)避免在構造函數中使用'async void')。 –
'GetAuthorizationUriAsync()'獲取第一個'await'。它永遠不會到達第二個。 – sohum