Search code examples
c#wpfdropbox-api

Why does the Dropbox API's "DownloadAsync" method freeze when run in an async Task<bool> method. C#


So, I use the Dropbox API in my C# application to download files and check strings. Previously, I've always used the "DownloadAsync" method to download a file and get it's contents in an "async void" method. Recently, however, I also needed to return a boolean, so I put the same code that I've always used in an "async Task" method, so that I could check the result. However, when I do this, the "DownloadAsync" method never finishes (runs forever). If I take the same method and put it in an "async void" method (without returning a result) the "DownloadAsync" method finishes just fine. I'm not sure why this makes a difference at all, but it does.

In this first method, the "keysToCheck" string gets set, boolean gets set, and method finishes.

private async void SetStringAndBoolean(string text)
    {
        var keysToCheck= "";
        bool booleanToCheck;

        using (var dbx = new DropboxClient("TOKEN"))
        {
            using (var response = await dbx.Files.DownloadAsync("/FileToDownload.txt"))
            {
                keysToCheck = await response.GetContentAsStringAsync();
            }
        }

        var keys = keysToCheck.Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList();

        foreach (var key in keys)
            if (key == text)
                booleanToCheck = true;

        booleanToCheck = false;
    }

However, in the following method, the "DownloadAsync" method never finishes. It just runs forever. Any ideas what I'm doing wrong?

private async Task<bool> SetStringAndReturnBoolean(string text)
    {
        var keysToCheck = "";

        using (var dbx = new DropboxClient("TOKEN"))
        {
            using (var response = await dbx.Files.DownloadAsync("/FileToDownload.txt"))
            {
                keysToCheck = await response.GetContentAsStringAsync();
            }
        }

        var keys = keysToCheck.Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList();

        foreach (var key in keys)
            if (key == text)
                return true;

        return false;
    }

Calling Method (Button Click Event):

private async void Button_Click(object sender, RoutedEventArgs e)
    {
        if (!SetStringAndReturnBoolean(GuiTextBox.Text).Result)
            ErrorRun.Text = "Invalid Key";
        else
        {
            DialogResult = true;
            Close();
        }
    }

Solution

  • Use await to call the method instead of accessing Result of the returned Task.

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        bool result = await SetStringAndReturnBoolean(GuiTextBox.Text);
        if (!result)
        {
            ErrorRun.Text = "Invalid Key";
        }
        else
        {
            DialogResult = true;
            Close();
        }
    }
    

    Async only works when you use it consistently. Never mix await and Task.Result or Task.Wait() unless you know very well what you do.