Awaited Async call in ViewDidLoad() not awating

hjavaher1hjavaher1 USMember ✭✭

Hi,
I'm having an issue where I'm trying to fetch a user's profile from a web server. This call resided inside ViewDidLoad() like follows:

var result = await FetchProfile();

Inside Fetch Profile resides the actual awaited http call to the server. The problem is that the await does not stop the execution until it's complete. The execution continues along and crashes as soon as a member of the result is needed. As soon as this happens, I get a null ref exception and the application crashes.

Can anyone help please? What am I missing?

Thanks,
Jason

Tagged:

Answers

  • SebastianKruseSebastianKruse USMember ✭✭✭

    Did you make another async call inside of "FetchProfile" and miss the await on that?

  • TedRogersTedRogers USMember ✭✭✭✭

    Keep in mind that await will not halt the lifecycle of your view controller. Execution is not "stopped". If you set a breakpoint right after your await call, do you hit it immediately? That is all you can really expect to happen with await.

  • hjavaher1hjavaher1 USMember ✭✭

    @Sebastian, No I have not forgotten any awaits in the FetchProfile method.

    @Ted, I could be wrong and please correct me if I am, but I do believe the whole purpose of the await is to stop the execution and release the thread until such time as the Async call is completed. At that time, it should pick up where it left off and continue execution. How else are you suppose to make Async calls and utilize the resulting object?

  • JGoldbergerJGoldberger USMember, Forum Administrator, Xamarin Team, University Xamurai
    edited March 2017

    Can you share the full code of the ViewDidLoad method and the FetchResult method?

    In general, async void should not be used except in event handlers, yet if you want to make ViewDidLoad async, you have no choice but to leave the return type as void. So this is not ideal use of async/await. However a quick test on my end worked as expected doing the following:

    public override async void ViewDidLoad()
        {
            base.ViewDidLoad();
            // Perform any additional setup after loading the view, typically from a nib.
            label.Text = "Loading data..."l
            var result = await FetchProfile();
            label.Text = result;
        }
    
    async Task<string> FetchProfile()
        {
            var client = new HttpClient();
            string response = await client.GetStringAsync("https://example.com");
            return response;
        }
    

    This worked and my label did show up with text "Loading data..." and then once the response from the async call was achieved, the label text was updated with the results from example.com. This is what should happen. i.e. the ViewDidLoad method will return control to iOS when await FetchProfile() is called so that the view can actually be displayed, keeping the UI responsive, which is generally desirable and one reason why we use async in the first place. Then when the FetchProfile() method returns, the rest of the code in ViewDidLoad runs.

  • hjavaher1hjavaher1 USMember ✭✭

    Hi Jon,
    After hours of debugging I found the underlying issue. Unfortunately I don't yet know the solution to this issue. The issue (at lease as far as I can tell) is that within the FetchProfile() method, I'm calling a static class that is in charge of making the actual http web request to my webapi.

    To be honest, I don't understand what the problem is with this but know that this quite possibly could be the issue. Does that sound about right?

    anyways, I have taken out all of the irrelevant code below but the calls are as follows and ofcourse, FetchProfile is called in the ViewDidLoad() method.

    Code:

    private async Task<bool> FetchProfile()
    {
    ...
        var profile = GetUserProfile(guid);
        ...
    }
    
    
    //This code is in the Portable Shared Library in the project
    public static async Task<ProfileTable> GetUserProfile(Guid profileId)
     {
    ...
        var result = await client.GetAsync("/api/account/localinfo" + profileId);
        return result;
        ...
     }
    

    Thanks,
    Hiva

  • JGoldbergerJGoldberger USMember, Forum Administrator, Xamarin Team, University Xamurai
    edited March 2017

    @HivaJavaher.3885

    Ah, I think I see the issue. Try this:

    private async Task<bool> FetchProfile()
    {
        ...
        var profile = await GetUserProfile(guid); // <-- add await keyword
        ...
     }
    

    By not awaiting that call, the FetchProfile method is returning before the GetUserProfile task is done, and this then lets the ViewDidLoad method continue as well.

  • hjavaher1hjavaher1 USMember ✭✭

    @JonGoldberger.4124
    ugh, I'm sorry, that was my transcribing mistake. The GetUserProfile(guid) does have an await on it.

  • JGoldbergerJGoldberger USMember, Forum Administrator, Xamarin Team, University Xamurai

    @HivaJavaher.3885
    Well somehow, somewhere. something is not properly being awaited as far as I can tell.

    Also to ping me use @JGoldberger I don't know who the impostor @JonGoldberger.4124 is. :-)

  • hjavaher1hjavaher1 USMember ✭✭

    @JGoldberger I've now gone through the code back and fort, there are no async calls that are not awaited unfortunately. Could it be because I'm using an static method inside a static class in the portable class library? I read something about this being the cause.

  • JGoldbergerJGoldberger USMember, Forum Administrator, Xamarin Team, University Xamurai

    @HivaJavaher.3885

    Could it be because I'm using an static method inside a static class in the portable class library? I read something about this being the cause.

    I don't see why that is the case and I could not find anything that says so. Do you have a link to what you read? Also an easy test to see if it is the issue would be to make the class and method not static, create an instance of the class and call the async method and see if the results change.

Sign In or Register to comment.