HttpClient GetAsync freezes

Issue

After authorization, the contact page is loaded. The method is called in the viewmodel page.

public partial class Contacts : ContentPage
        {
            ContactsPageViewModels vm;    
            public Contacts()
            {
                vm  new ContactsPageViewModels();
                BindingContext  vm;
                InitializeComponent();
            }
         }

I tried to send just 200ok. Everything comes to the http analyzer, but in the application itself it hangs on the first line

public async Task<ObservableCollection<UserModel>> GetContactsList()
        {
            //freezes in the first line
            var response  await client.GetAsync("http://localhost:52059/api/Home/GetContacts/" + Convert.ToString(App.User.ID));
            string responseBody  await response.Content.ReadAsStringAsync();
            return JsonConvert.DeserializeObject<ObservableCollection<UserModel>>(responseBody);
        }

Controller

        [HttpGet]
        [Route("GetContacts/{id}")]
        public ActionResult GetContacts(int id)
        {
            ObservableCollection<UserModel> users  new ObservableCollection<UserModel>();

            foreach (UserModel user in db.UserModels)
                users.Add(user); 

            users.Remove(db.UserModels.FirstOrDefault(u > u.ID  id));

            Response.Headers.Add("Content-Type", "application/json");

            //return Ok();
            return new JsonResult(users);
        }

In postman all work

Solution

It sounds like a problem with synchronization context and being on the main thread of the application.

Read more here or here.

Try:

public async Task<ObservableCollection<UserModel>> GetContactsList()
{
    var response  await client.GetAsync("http://localhost:52059/api/Home/GetContacts/" + Convert.ToString(App.User.ID)).ConfigureAwait(false);
    string responseBody  await response.Content.ReadAsStringAsync().ConfigureAwait(false);
    return JsonConvert.DeserializeObject<ObservableCollection<UserModel>>(responseBody);
}

What happens is a deadlock, because the main thread is waiting for the async to end. And async want to get back to the thread an end async – but cannot, because the main thread is waiting for it.

.ConfigureAwait(false)

will say (not digging into the state machine and how async/await works) that it will end on some other thread, that the calling (main/synchronization) thread.

Answered By – Piotr

Leave a Comment