3

I'm trying to download a large file (500 mb) from my webserver using WPF and MVVM. Thus the following properties are all bound to some kind of controls (progressbar). The problem is, that the application still hangs, even while using DownloadFileAsync.

The file is being downloaded as I can tell from my logs (and the file growing, of course).

This is my code:

    #region Methods

    private void StartDownload(string url, string localPath)
    {
        Logger.Debug("Starting to initialize file download");

        if (!_webClient.IsBusy)
        {
            _webClient = new WebClient();
            _webClient.Proxy = null; // http://stackoverflow.com/questions/754333/why-is-this-webrequest-code-slow/935728#935728
            _webClient.DownloadFileCompleted += webClient_DownloadFileCompleted;
            _webClient.DownloadProgressChanged += webClient_DownloadProgressChanged;

            _webClient.DownloadFileAsync(new Uri(url), localPath);
        }

        Logger.Debug("Finished initializing file download");
    }

    private void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
    {
        Logger.Debug("Download finished! Cancelled: {0}, Errors: {1} ", e.Cancelled, e.Error);
    }

    private void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    {
        Logger.Debug("Downloading... Progress: {0} ({1} bytes / {2} bytes)", e.ProgressPercentage, e.BytesReceived, e.TotalBytesToReceive);

        if (!IsDownloadPaused)
        {
            DownloadFileProgress = e.ProgressPercentage;
            BytesReceived = e.BytesReceived;
            TotalBytesToReceive = e.TotalBytesToReceive;
        }
        else
        {
            Logger.Debug("Download paused...");
        }
    }

    #endregion Methods

Edit as per comment request: It's a .NET 4 CP application, thus no async or await. The entire application is going responseless, no window resizing, button clicking or textbox-interaction at all.

When I break in with the debugger, I keep hanging in the OnPropertyChanged()-Method (I think because that's where most of the time goes by) and get the following call stack:

Launcher.exe!Company.Product.Tools.Launcher.ViewModels.ViewModelBase.OnPropertyChanged(string propertyName) Line 16 + 0x59 bytes    C#
Launcher.exe!Company.Product.Tools.Launcher.ViewModels.DownloadViewViewModel.BytesReceived.set(long value) Line 82 + 0x21 bytes C#
Launcher.exe!Company.Product.Tools.Launcher.ViewModels.DownloadViewViewModel.webClient_DownloadProgressChanged(object sender, System.Net.DownloadProgressChangedEventArgs e) Line 216 + 0x3f bytes  C#

It doesn't hang there, when stepping further it goes without any delay.

SeToY
  • 5,777
  • 12
  • 54
  • 94
  • 1
    Could you elaborate on "hangs" - is it the full works, with no UI events at all (e.g. window resizing) getting a look-in? What happens if you break in with the debugger - what does the call stack look like? – Jon Skeet May 31 '13 at 21:17
  • Have you tried making StartDownload async? – Michael Skarum May 31 '13 at 21:18

1 Answers1

7

It sounds like you're getting lots of feedback about the number of bytes downloaded, and the property changed event handler is relatively inefficient. Maybe you should only limit how often you update BytesReceived - either by time (e.g. update it five times per second) or by delta (update it when it's changed by more than a K) or some hybrid version.

You might also want to look into what's happening in the property though - see whether there's anything inefficient there which you could optimize.

(The first step might be to keep a count of just how many times webClient_DownloadProgressChanged is called.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Alright, a quick test (commenting out the assignment of `BytesReceived`) has kept the UI responsive (button interaction possible)... I think that's the problem and the perpetual PropertyChanged() has caused the UI to go crazy. Thank you! – SeToY May 31 '13 at 21:30