0

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();

    }
  • For those looking for a solution to this problem, I found what worked for me [here](http://stackoverflow.com/questions/32501683/c-sharp-flurl-and-httpclient-no-response-from-rest-api) – Chris Goetz Dec 24 '16 at 00:03

2 Answers2

1

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 awaiting your call to Auth(), which is really the equivalent of just calling client.Authorize() without await or GetResult() directly from your MainWindow() constructor. You're no longer blocking, but you are fire-and-forgetting, meaning any exceptions that might occur in client.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 call MainAsync().Wait() from Main.) 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:

private async void MainWindow_Load(object sender, System.EventArgs e)
{
    await client.Authorize();
}
Todd Menier
  • 37,557
  • 17
  • 150
  • 173
  • 1
    Yep. Walked away from it and came back with fresh eyes to see my mistake(s). I went back and found a few lines of code that were blocking in the library I built. Testing for about 4 hours solid now without a single issue. The flurl implementation made things much easier to troubleshoot and drastically reduced the lines of code. Appreciate your answer and the awesome library. – Chris Goetz Dec 25 '16 at 00:26
0

This is what worked but I'm still not sure why...

    private Client client;
    public MainWindow()
    {
        InitializeComponent();
        var vault = new Vault();
        client = new Client(vault.GetAccountId(), vault.GetApiKey());
        Auth();

    }

    private async void Auth()
    {
        await client.Authorize();
    }

Wrapping the authorization call in an async method allowed the httpPost to complete and return results.