friartuck
friartuck

Reputation: 3121

Getting async result deadlocking (despite setting configure await to false)

I'm doing some OAuth work, where I get my refresh token through an provided async API method (GetRefreshTokenAsync):

public async Task<Tokens> RenewAuthentication()
{
    AppTokenResult token = await OAuth.GetRefreshTokenAsync("clientid",
      "clientsecret", 
    @"myRefreshToken");

    string accessToken = token.AccessToken;
    string refreshToken = token.RefreshToken;

    return new Tokens(accessToken, refreshToken);

}

If I call this like from a non-async method as such:

public void noAsync()
{
    var r = RenewAuthentication();
    var x = r.Result;
}

It deadlocks the app :(. If I remove the 2nd line (r.Result), then it works, but that's crap, because I can't get the result. I tried reading

http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

But after trying his method 1 by adding .ConfigureAwait(false) to the GetRefreshTokenAsync() method it didn't make any difference.

Any advice?

Upvotes: 2

Views: 1083

Answers (4)

Luaan
Luaan

Reputation: 63722

You need to make sure the result of RenewAuthentication isn't marshalled back to the UI thread. ConfigureAwait(false) is pretty much exactly for a purpose like this:

var renewAwaitable = RenewAuthentication().ConfigureAwait(false);
var result = renewAwaitable.GetAwaiter().GetResult();

However, I'd suggest with going all-out with async instead. There isn't really a reason to block anywhere in a UI application - just disable whatever controls must not be used while waiting for the token to come back, and enable them when it does.

Upvotes: 1

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149518

It deadlocks the app :(

That's what blocking on an async method in an environment that has a custom synchronization will do.

If you call this on "FormLoad", you don't need to block. Simply mark you event handler as async so you can await on the operation:

public Form()
{
    this.Load += OnLoadHandler;
}

public async void OnLoadHandler(object sender, EventArgs e)
{
    var result = await RenewAuthenticationAsync();
    // Store the result here
}

Upvotes: 5

Gusdor
Gusdor

Reputation: 14334

async code is an all the way construct. You cannot do half async and should not try to force it. noAsync appears to do nothing useful here.

In his wisdom, Mr Cleary makes it clear that each async method has its own context in which it may run continuation on the UI.

Can you be sure that OAuth.GetRefreshTokenAsync is using ConfigureAwait(false) internally? If it doesn't, you will deadlock.

Upvotes: -1

Norbert
Norbert

Reputation: 41

If you access the Result property of a Task, it will act as a Future and it will block the current thread until the Task returns with the result.

I don't think you actually got a deadlock, but the Task you're waiting for never finishes.

Make sure your call to OAuth.GetRefreshTokenAsync returns.

Upvotes: 1

Related Questions