Konstantin Severy Konstantin Severy - 10 months ago 53
C# Question

Calling a WebAPI asynchronously from a Xamarin.Android event handler deadlocks

I've been struggling with this issue for a while and it's now time for me to ask my question here. So, here's the situation:

I've got a WebAPI, a Xamarin.Android application and an IdentityServer4 implementation. The Xamarin.Android app needs to call the WebAPI to get a list of users based on a search. This is done via an async call in a TextChanged event handler. What happens is that when the call to the WebAPI is awaited, it never returns and at some point the task gets cancelled. I've tried using ConfigureAwait(false), I've made the event handler method async void, I've read through several other questions on here about similar issues - none of the options work for me. But here's some code for you to get an idea of what I've doing:

The TextChanged handler:

protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);

SetContentView(Resource.Layout.SearchPeopleLayout);

this.searchUsersElement = FindViewById<EditText>(Resource.Id.searchUsersField);
this.usersListElement = FindViewById<ListView>(Resource.Id.usersSearchResult);

using (var scope = App.Container.BeginLifetimeScope())
{
this.apiClient = App.Container.Resolve<IUsersApiClient>();
}

this.searchUsersElement.TextChanged += SearchUsersElement_TextChanged;
}

public async void SearchUsersElement_TextChanged(object sender, Android.Text.TextChangedEventArgs e)
{
var length = e.Start + e.AfterCount;
if (length <= MinUsernameLength)
{
return;
}

var searchName = string.Join(string.Empty, e.Text);

var users = await this.apiClient.GetUsers(searchName, Persistor.ApiClient);

RunOnUiThread(() =>
{
var usersAdapter = new UsersAdapter(this, users.ToList());

this.usersListElement.Adapter = usersAdapter;
});
}


Here's the UsersApiClient implementation:

public async Task<IEnumerable<UserModel>> GetUsers(string username, HttpClient client)
{
try
{
var content = await client.GetStringAsync($"{apiUrl}/users?name={username}").ConfigureAwait(false);

var result = JsonConvert.DeserializeObject<IEnumerable<UserModel>>(content);

return result;
}
catch (Exception ex)
{
throw ex;
}

}


The deadlock happens on the GetStringAsync() call. I've tested the call that it makes via Postman and it is giving me the correct response. Only things I haven't tried yet are implementing the ITextWatcher interface instead of adding an event handler, and changing the code so I don't use a separate method but rather an anonymous delegate - I read in some places that that could prove to be an issue.

I'm really hoping some of you can help me in resolving this issue and making me understand how to do such asynchronous calls correctly.

Best regards.

Answer Source

Okay, so I'm not really sure what fixed the issue, but here's what I did - there was another StackOverflow question with a similar problem where the problem was solved with uninstalling the app from the emulator manually before redeploying it. I also removed the ConfigureAwait(false) call. And suddenly, everything's working. Not sure how it happened, but here it is - uninstalling the app manually and calling the API without the ConfigureAwait(false) did it.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download