Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HttpClient.GetAsync never returns on Xamarin.Android

I am working on an Android application, backed up by an ASP.NET Core application hosted on Azure. I am using a shared Library project to test basic stuff on a Console Application project before making the functionalities for the Xamarin.Forms (Android-only) project.
The following piece of code is run after logging into the web service, where Client is a HttpClient:

public static async Task<MyClass> GetInformationAsync(string accountId)
{
    HttpResponseMessage response = await Client.GetAsync(UriData + "/" + accountId);
    response.EnsureSuccessStatusCode();
    string responseContent = await response.Content.ReadAsStringAsync();
    return JsonConvert.DeserializeObject<MyClass>(responseContent);
}

Under the same computer/network, the code finishes in less than a second on the Console application, however, it never finishes (even waited a minute) in the Xamarin.Forms.Android project.
I find this weird since the Android client can successfully login to the web service using PostAsync.

There is a difference, however, on how the Android client and the Console client call GetInformationAsync.

While the Console client calls it asynchronously:

 private static async void TestDataDownload()
 {
      ...
      var data = await WebApiClient.GetInformationAsync(myId);
 }

The Android client calls it synchronously

 public void MainPage()
 {
      ...
      var data = WebApiClient.GetInformationAsync(myId).Result;
 }
like image 528
Camilo Terevinto Avatar asked Jun 29 '16 00:06

Camilo Terevinto


1 Answers

It seems like you are experiencing a deadlock of some sort. You might want to include the code where you actually call GetInformationAsync, as it is probably where the problem source is.

You can probably fix your issue by:

  1. Not calling GetInformationAsync in a sync way
  2. Postfixing your async calls in GetInformationAsync with ConfigureAwait(false) to not switch context on every method call.

So your GetInformationAsync method would look like:

public static async Task<MyClass> GetInformationAsync(string accountId)
{
    var response = await Client.GetAsync(UriData + "/" + accountId).ConfigureAwait(false);
    response.EnsureSuccessStatusCode();
    var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
    return JsonConvert.DeserializeObject<MyClass>(responseContent);
}

Then if you call it somewhere you need it to return back on the same context, I.e. if you need to update UI:

var myClass = await GetInformationAsync(accountId);
// update UI here...

Otherwise if you don't need to return on the same context:

var myClass = await GetInformationAsync(accountId).ConfigureAwait(false);
like image 50
Cheesebaron Avatar answered Sep 22 '22 22:09

Cheesebaron