Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebClient.DownloadProgressChanged never gets called

Tags:

c#

.net

I added an event handler to the WebClient's DownloadProgressChanged event, but it never seems to fire. The file successfully downloads, but without having its progress updated.

public class DownloadFile
{
    private File file = null;

    public DownloadFile(File file)
    {
        this.file = file;
    }

    public void startDownloadThread()
    {
        Console.WriteLine("Starting Download : "+file.URL);

        var t = new Thread(() => DownloadThread(file));
        t.Start();
    }

    public Action<string> action_error_downloadFailed = Console.WriteLine;
    private void DownloadThread(File file) //Unnecessary argument but whatever ;D
    {
        try
        {
            string url = file.URL;
            string savepath = file.DestinationDir + "\\" + file.Filename;

            WebClient_B client = new WebClient_B();
            client.Proxy = null; //default to no proxy
            client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
            client.DownloadFile(url, savepath);

            Console.WriteLine("Download finished :" + file.Filename);
        }
        catch (Exception ex)
        {
            if (action_error_downloadFailed != null)
                action_error_downloadFailed("Download failed :"+ex.Message);
        }
    }

    private void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    {
        try
        {
            if (file.TotalSize == 0)
                file.TotalSize = (int)e.TotalBytesToReceive;
            file.CurrentSize = (int)e.BytesReceived;

            Form_DownloadManager.rebuildQueue();

            Console.WriteLine("{0}    downloaded {1} of {2} bytes. {3} % complete...",
            (string)e.UserState,
            e.BytesReceived,
            e.TotalBytesToReceive,
            e.ProgressPercentage);
        }
        catch (Exception ex) { Console.WriteLine("client_DownloadProgressChanged error : "+ex.Message); }
    }
}

Output:

Starting Download : http://x.x.x/y/z.zip
'projectname.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
The thread '<No Name>' (0x3b8c) has exited with code 0 (0x0).
Download finished :z.zip

I am using WebClient_B because I had to add useragent+cookiecontainer functionality to the WebClient class since my server kept rejecting the download request. The event never fired with the 'standard' WebClient class either, though. So that shouldn't be the problem. But anyway; link to class

like image 791
natli Avatar asked Jun 13 '12 12:06

natli


2 Answers

client.DownloadFile(url, savepath);

You have to use the async version to download a file, currently you use the blocking, synchronous version.

From the msdn docs for WebClient.DownloadProgressChanged:

Occurs when an asynchronous download operation successfully transfers some or all of the data.

In your case that would be:

client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadFileAsync (url, savepath);

Since your method does not directly return any result, this refactoring shouldn't be a problem, note though that the download most likely has not been completed by the time the method returns to the caller.

like image 62
BrokenGlass Avatar answered Nov 09 '22 03:11

BrokenGlass


If you want to use WebClient synchronously, while getting progress updates, you can rely on this method detailed here:

http://alexfeinberg.wordpress.com/2014/09/14/how-to-use-net-webclient-synchronously-and-still-receive-progress-updates/

public void DownloadFile(Uri uri, string destination)
{
  using (var wc = new WebClient())
  {
    wc.DownloadProgressChanged += HandleDownloadProgress;
    wc.DownloadFileCompleted += HandleDownloadComplete;

    var syncObject = new object();
    lock (syncObject)
    {
       wc.DownloadFileAsync(uri, destination, syncObject);
       // This would block the thread until download completes
       Monitor.Wait(syncObject);
    }
  }
 
  // Do more stuff after download was complete
}

private void HandleDownloadComplete(object sender, AsyncCompletedEventArgs args)
{
   lock (args.UserState)
   {  
      // releases blocked thread
      Monitor.Pulse(args.UserState);
   }
}


private void HandleDownloadProgress(object sender, DownloadProgressChangedEventArgs args)
{
  // Process progress updates here
}
like image 37
user195275 Avatar answered Nov 09 '22 03:11

user195275