xCasper
xCasper

Reputation: 123

Code is skipping back to calling function after await call

I am trying to quickly hack together a basic mobile app with Xamarin to hit a local API. I made a default Xamarin.Forms PCL project in VS2015 and have attempted to add in code to hit an API that I have running locally. However, when I get to the line var response = await client.GetAsync(uri), the code executes and immediately jumps back to the line after RefreshDataAsync(), thus bypassing half a function, including the catch and finally block of the try/catch statement. I have gone as far as to add breakpoints to every line in the app and it 100% does not call any code beyond the await GetAsync call.

After hours I have to admit I am at a loss as to what the heck is happening in this app as I have never had issue with await/async before.

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using Xamarin.Forms;

namespace consumerestful
{
    public class App : Application
    {
    private List<Person> people;

    public App()
    {
        // The root page of your application
        RefreshDataAsync();
        var test = people;

        var content = new ContentPage
        {
            Title = "consumerestful",
            Content = new StackLayout
            {
                VerticalOptions = LayoutOptions.Center,
                Children = {
                    new Label {
                        HorizontalTextAlignment = TextAlignment.Center,
                        Text = "Welcome to Xamarin Forms!",
                    }
                }
            }
        };

        MainPage = new NavigationPage(content);
    }

    protected override void OnStart()
    {
        // Handle when your app starts
    }

    protected override void OnSleep()
    {
        // Handle when your app sleeps
    }

    protected override void OnResume()
    {
        // Handle when your app resumes
    }

    public async void RefreshDataAsync()
    {
        HttpClient client;
        client = new HttpClient();
        client.MaxResponseContentBufferSize = 256000;

        //RestUrl = http://127.0.0.1:5000/api/
        var uri = new Uri(Constants.RestUrl);
        try
        {                
            var response = await client.GetAsync(uri);//problem line
            //nothing after the above line runs. It jumps back to Line 19(var test = people)

            var test = response;

            if (response.IsSuccessStatusCode)
            {
                var content = await response.Content.ReadAsStringAsync();
                people = JsonConvert.DeserializeObject<List<Person>>(content);
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine(@"              ERROR {0}", ex.Message);
        }
        finally
        {
            Debug.WriteLine(@"              Finally Block Ran!");
        }
    }
  }
}

Upvotes: 1

Views: 1838

Answers (1)

Kevin Le - Khnle
Kevin Le - Khnle

Reputation: 10857

The function RefreshDataAsync() is async as you defined it. But when you call it in the constructor, you can not call it with await because the constructor call is not async. Therefore you called the way that you showed, and because in that way, the call is not awaited, the execution flow of the program continues before that call is completed.

So the right way to refresh you data is to call RefreshDataAsync() with the await keyword in OnAppearing() and mark OnAppearing with async. Note that Intellisense might complain that you should return Task but you can't do that either because that's not what's defined in the base class. So I think you can leave it as void. Here's how you can change your code to:

public App()
{
    var content = new ContentPage
    {
        Title = "consumerestful",
        Content = new StackLayout
        {
            VerticalOptions = LayoutOptions.Center,
            Children = {
                new Label {
                    HorizontalTextAlignment = TextAlignment.Center,
                    Text = "Welcome to Xamarin Forms!",
                }
            }
        }
    };

    MainPage = new NavigationPage(content);
}

public async override void OnAppearing()
{
    // The root page of your application
    await RefreshDataAsync();
    var test = people;
}

Just a suggestion here. You might also want to restructure your code by moving the try catch around, but that was not the point of your question.

Upvotes: 1

Related Questions