Why does this download the large file, but hang the UI thread?

static async void DownloadData(TextBox textboxURL, TextBlock outputView)
{
    try
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri(textboxURL.Text);
            client.Timeout = TimeSpan.FromMinutes(1);

            var request = new HttpRequestMessage(HttpMethod.Get, textboxURL.Text);

            /// Fixed thanks to: http://stackoverflow.com/questions/18720435/httpclient-buffer-size-limit-exceeded
            HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
            /// Version = response.Version.ToString();
            response.EnsureSuccessStatusCode();
            // Result = await response.Content.ReadAsStringAsync();
            // Task<Stream> inputStream = response.Content.ReadAsStreamAsync();

            /// DUPE CODE: var sendTask = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
            /// NEED TO READ UP ON THIS: response..Result.EnsureSuccessStatusCode();
            var httpStream = await response.Content.ReadAsStreamAsync();

            var picker = new FileSavePicker()
            {
                SuggestedStartLocation = PickerLocationId.Downloads,
                SuggestedFileName = "DOWNLOADING.BIN"
            };

            picker.FileTypeChoices.Add("Any", new List<string>() { "." });
            /// picker.FileTypeChoices.Add("Any", new List<string>() { "*" });

            StorageFile storageFile = await picker.PickSaveFileAsync();

            // Woohoo!  Got it working using await, and removing the Task<> wrapper!
            using (var reader = new StreamReader(httpStream))
            {
                Stream fileStream = await storageFile.OpenStreamForWriteAsync();

                httpStream.CopyTo(fileStream);
                fileStream.Flush();
            }
        }
    }
    catch (Exception ex)
    {
        outputView.Text = "Error, try again!";
        var dlg = new Windows.UI.Popups.MessageDialog(ex.Message, "Error");
        await dlg.ShowAsync();
    }
}
Jon Skeet
people
quotationmark

You're using the synchronous Stream.CopyTo method here:

httpStream.CopyTo(fileStream);

I think you just want:

await httpStream.CopyToAsync(fileStream);

However, you should also remove the StreamReader part - you're not using the StreamReader, and it's possible that it will try to read some data to detect the encoding. However, you should use a using statement for the storage file. So basically, change this:

using (var reader = new StreamReader(httpStream))
{
    Stream fileStream = await storageFile.OpenStreamForWriteAsync();

    httpStream.CopyTo(fileStream);
    fileStream.Flush();
}

to:

using (Stream fileStream = await storageFile.OpenStreamForWriteAsync())
{
    await httpStream.CopyToAsync(fileStream);
}

people

See more on this question at Stackoverflow