簡體   English   中英

使用httpclient的任務並返回無法正常工作的值

[英]Task using httpclient and returning a value not working correctly

我環顧四周,並遵循了一些有關如何進行此設置的教程,但我沒有運氣。 我正在使用Xamarin構建跨平台應用程序。 我有一個可移植的類庫來處理我的所有業務邏輯和Web服務調用。

我遇到的問題是,當我在下面的方法中運行代碼時,它可以正常工作,但是如果我將其作為任務運行,如下圖所示,則需要很長時間。 我相信它陷入僵局,但是由於我是新手,所以我不明白為什么。 我希望我的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); 然后它什么都不做。 關於我在做什么的任何想法。 感謝您的任何幫助。

參考本文Async / Await-異步編程的最佳實踐

“一路異步”意味着您應在不仔細考慮后果的情況下混合使用異步代碼。 特別是,通過調用Task.Wait或Task.Result阻止異步代碼通常是一個壞主意。 對於程序員來說,這是一個特別普遍的問題,他們將自己的腳步“浸入”異步編程中,只轉換其應用程序的一小部分並將其包裝在同步API中,從而使應用程序的其余部分不受更改的影響。 不幸的是,它們遇到了死鎖問題。 在MSDN論壇,Stack Overflow和電子郵件上回答了許多與異步相關的問題之后,我可以說這是迄今為止異步新手提出的最基本的問題:“為什么我的部分異步代碼會死鎖?”

不要混用阻塞代碼和異步代碼。 您應該一直使用Async。 您的死鎖是因為.Result被阻止。

你想做...

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

總結第二條指南,您應該避免混合使用異步代碼和阻塞代碼。 異步和阻塞代碼混合會導致死鎖,更復雜的錯誤處理以及上下文線程的意外阻塞。 本指南的例外情況是控制台應用程序的Main方法,或者(如果您是高級用戶)是管理部分異步代碼庫的方法。

在使用按鈕EventHandler的情況下,您將執行以下操作:

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)
        }

您可以在此處找到有關避免死鎖的更多信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM