2016-05-01 33 views
0

我環顧四周,並關注瞭如何設置這些的教程,我沒有運氣。我正在使用Xamarin構建一個跨平臺的應用程序。我有一個可移植的類庫來處理我所有的業務邏輯和Web服務調用。使用httpclient並返回值無法正常工作的任務

我遇到的問題是當我在下面的方法中運行代碼而沒有問題時,但是如果我按照下面所示的方式運行它作爲一個任務需要很長時間。我相信它已經陷入僵局,但由於我對此很陌生,所以我不明白爲什麼。我希望我的Api調用位於PCL中,因此我可以在每個平臺之間共享它。

public async Task<LoginResponse> Login(string userName, string password) 
{ 
    HttpClient client = new HttpClient(); 
    string baseUrl = "http://someURLhere/"; 

    client.BaseAddress = new Uri(baseUrl); 

    string authData = string.Format("/IOSLogin?Username={0}&Password={1}&languageSettingOnDevice={2}", userName, password, "en"); 

    var uri = new Uri(string.Format("{0}{1}", baseUrl, authData)); 

    var response = await client.GetAsync(uri); 
    if (response.IsSuccessStatusCode) 
    { 
     var content = await response.Content.ReadAsStringAsync(); 

     LoginResponse jsonResponse = JsonConvert.DeserializeObject<LoginResponse>(content); 
     jsonResponse.loginSuccesfull = true; 
     return jsonResponse; 
    } 
    else 
    { 
     return new LoginResponse() { loginSuccesfull = false }; 
    } 
} 

在ios版本的項目中,在按鈕事件上,我使用此代碼運行上面顯示的任務。

Core.Service.AtmisService service = new Core.Service.AtmisService(); 
LoginResponse loginTask = service.Login(userName.Text, password.Text).Result; 

我認爲,通過這種方式設置它,當我在調用任務的末尾使用.Result將執行這一任務並返回結果。我添加了斷點,並且它進入登錄方法,並且達到這個var response = await client.GetAsync(uri);,然後它什麼都不做。關於我做錯什麼的想法。感謝您的任何幫助。

回答

1

引用本文Async/Await - Best Practices in Asynchronous Programming

「異步一路」意味着你不應該沒有仔細考慮後果混合同步和異步 代碼。特別是在 中,通過調用 Task.Wait或Task.Result來阻止異步代碼通常是一個壞主意。這是一個特別常見的問題,因爲編程人員正在將他們的「腳趾頭」編程到異步編程中,只將應用程序的一小部分轉換成同步API,因此應用程序的其餘部分是 與變化隔離。不幸的是,他們遇到了 死鎖的問題。回答了許多關於MSDN 論壇,堆棧溢出和電子郵件的異步相關問題後,我可以說這是迄今爲止最常見的問題,一旦他們學習了基本知識,他們就會被異步新人問到: 「爲什麼我的部分異步代碼死鎖?「

不要混合使用阻塞和異步代碼。你應該一直走異步。你的僵局是因爲.Result被阻止。你想要做

...

LoginResponse loginTask = await service.Login(userName.Text, password.Text); 

總結本次指導,你應該避免混合異步和 阻止代碼。混合異步和阻止代碼可能導致死鎖, 更復雜的錯誤處理和意外阻塞的上下文 線程。本指南的例外是 控制檯應用程序的Main方法,或者如果您是高級用戶,則管理 部分異步代碼庫。

+0

謝謝您的明確解釋,現在變得更有意義。 –

0

在使用按鈕事件處理程序,你會做這樣的事情你的情況:

private async void myButtonItem_Clicked(object sender, EventArgs e) 
     { 
      Core.Service.AtmisService service = new Core.Service.AtmisService(); 
      LoginResponse loginTask = await service.Login(userName.Text, password.Text).ConfigureAwait(false); 
      //The rest of the code in this method may run in a different thread than the one that invoked the method. If you have ui code after this then avoid using ConfigureAwait(false) 
     } 

你可以找到關於避免死鎖here更多信息。

相關問題