Quick background. Used Flurl inside a class library I built to simplify my code for communicating with a cloud storage api. Works beautifully when calling the library from a console app used to test all of the methods. When attempting to use the exact same class library with a simple winform, the same method that returns very quickly using the console app now seems to never return a result. When debugging, the code below gets to the ".GetAsync()" line and then never returns a result and also prevents the debug session from continuing. No error message is ever thrown.
I found a comment on the Flurl site that someone seemed to be having this same issue but, it doesn't seem like they posted the question here as was recommended. Anything that could point me in the right direction would be greatly appreciated.
Flurl code wrapped in async method
public async Task<AccountInfo> Authorize()
{
string credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(Utils.ToNonSecureString(accountId) + ":" + Utils.ToNonSecureString(applicationKey)));
var result = await B2UrlType.Authorize
.WithHeader("Authorization", "Basic " + credentials)
.GetAsync()
.ReceiveJson<AccountInfo>();
return result;
}
Console app calling code that works perfectly
if (client == null)
{
var vault = new Vault();
Console.WriteLine("Retrieving account keys");
client = new Client(vault.GetAccountId(), vault.GetApiKey());
Console.WriteLine("Successfully retrieved account keys");
Console.WriteLine("Created new client");
client.Authorize().GetAwaiter().GetResult();
}
Winform calling code that does not return
private Client client;
public MainWindow()
{
InitializeComponent();
var vault = new Vault();
client = new Client(vault.GetAccountId(), vault.GetApiKey());
client.Authorize().GetAwaiter().GetResult();
}
Your original code hangs because you're blocking the UI thread with your call to
GetResult()
. This is not a Flurl-specific problem; this is async 101.Your fix works because you're no longer blocking, but you're also not
await
ing your call toAuth()
, which is really the equivalent of just callingclient.Authorize()
withoutawait
orGetResult()
directly from yourMainWindow()
constructor. You're no longer blocking, but you are fire-and-forgetting, meaning any exceptions that might occur inclient.Authorize
will go unobserved, causing bugs that are hard to track down.Rule of thumb: Like with any async library, call Flurl's async methods from other async methods and await them whenever possible. In console apps, you have to block the main thread somewhere or the application will simply exit before tasks are complete. (I like to do it at the very top - define a
MainAsync
method containing all the work and callMainAsync().Wait()
fromMain
.) But with WinForms apps, there's a good place to put async code where you never have to block or fire-and-forget: Event handlers.I haven't done WinForms in a long while, but based on other answers it seems like a decent event for initialization code is
Window.Load
. Moving your authorization call there would be a good solution. Something like this: