Introduction
Downloading files over the network could be a cumbersome task. Trying to implement other features like auto-resume and support for proxy servers, etc. makes it even harder. Using this component can make things a lot easier for yourself. You can download files over proxies, password protected sites or untrusted SSL connections simply by setting a few properties. The example that is provided shows how to do the job and how to handle events over a simple GUI.
Since the download operation takes place in a worker thread asynchronously, you don't need to worry about downloading large files or blocking the user interface. There are some points you need to have in mind though.
Aborting the Worker Thread
Stopping a download operation that is running is tricky. You could just call the DownloadThread.Abort()
method on the downloader thread to stop the work, but this is not the recommended way. The main reason for this is that Thread.Abort
throws an exception which can occur at any time during your work and leaves your running state inconsistent. The easier way is to check for a boolean field, and terminate the operation when the field is set, or run the job on an entirely different process. To read more about this idea, check Ian Griffiths blog post here.
Updating GUI
When running a download job, the Downloader component provides its internal progress and error state through events and custom eventargs. Since the eventargs are constructed on the worker thread, trying to update the user-interface from the worker thread throws a Cross-Thread exception. The workaround to update the user interface is to use the Invoke
method (inherited from Control
), a Delegate and call to the necessary method(s), like this:
private delegate void ParamMethodInvoker
(long fileSize, long progressValue, string message);
private void OnDownloadProgressChanged
(object sender, DownloadProgressEventArgs e)
{
Invoke(new ParamMethodInvoker(UpdateProgress), new object[]
{ e.BytesRead, e.TotalBytes, e.Message });
}
private void UpdateProgress(long bytesRead, long totalBytes, string message)
{
int kbRead = Convert.ToInt32(bytesRead) / 1024;
int kbTotal = Convert.ToInt32(totalBytes) / 1024;
int percent = Convert.ToInt32((bytesRead * 100) / totalBytes);
progress.Value = percent;
lblDownloadMessage.Text =
string.Format("{0:#,###} of {1:#,###} KBytes ({2}%)",
kbRead, kbTotal, percent);
}
Resuming a Download
To resume a download job, we can simply continue where we left off. When restarting a download job, the downloader component first checks for the existing file at the specified location (through DownloadPath
property). If the file exists, it reads the Length
of the existing file and sets the HttpWebRequest
's range using AddRange
method. Overloads of the AddRange
method could be used to handle multi-part downloading of a single file.
long startingPoint = 0;
if(File.Exists(DownloadPath))
{
startingPoint = new FileInfo(DownloadPath).Length;
}
HttpWebRequest _Request = (HttpWebRequest)HttpWebRequest.Create(url);
_Request.AddRange(startingPoint);
Points of Interest
Implementing other features such as multi-part downloading (like download accelerator applications) and FTP downloads seems like a good idea. Any suggestions/comments/feedback are highly appreciated.
History
Version 1
- Provided the component with base features and events
- Provided a basic form to show features of the component