Click here to Skip to main content
11,636,598 members (75,091 online)
Click here to Skip to main content

An easy-to-use URL file downloader class for .NET

, 17 Aug 2007 CPOL 156.2K 2.3K 166
Rate this:
Please Sign up or sign in to vote.
A simple to use resumable file downloader class that provides progress feedback for .NET 2.0 or .NET 1.1

Introduction

For one of my projects at work, I needed the ability to download a file from a given URL. Unfortunately, the methods provided by the WebClient class don't do anything more than download the data. I needed something that gave the ability to provide progress feedback and that was resumable.

As I started my searches on the web for any existing code, I came across two articles on CodeProject that helped get me very close to what I needed. The first article was by John Batte, while the second article by Phil Crosby was a derivation of his work. Using both of these articles as a starting point, I was able to make another derivation that accomplished my goals.

The code samples and content of this article are focused on the .NET 2.0 implementation and any code updates have been made only to that version. The .NET 1.1 implementation is provided for backwards compatibility only and I have no further plans to continue making changes to it.

Using the Code

The FileDownloader class is the main class and is very simple to use. The minimal implementation is:

private void DoDownload()
{
    FileDownloader downloader = new FileDownloader();
    downloader.Download(new Uri("http://www.codeproject.com" +
        "/info/stuff/cp_bg_black1024.gif"), @"C:\Temp");
}

This creates a new instance of the FileDownloader class and downloads the file located at "http://www.codeproject.com/info/stuff/cp_bg_black1024.gif" to the "C:\Temp" folder.

FileDownloader actually performs all download operations asynchronously. When the FileDownloader.Download(Uri url, string destinationFolder) method is called, it accomplishes a synchronous download by waiting until a signal is set indicating that the download has completed. This allows for both synchronous downloads -- through the use of the Download methods -- or asynchronous downloads, through the use of the DownloadAsync methods. Both the synchronous and asynchronous methods ultimately call the same internal method to perform the actual download.

This internal method, called DownloadAsyncCore, instantiates an instance of the DownloadInfo internal class. This class is similar in nature to the FileInfo class provided by the .NET CLR and provides FileDownloader with all of the information required to actually download the file. This includes:

  • The length of the file being downloaded, if known
  • The Stream that is being used to actually download the file
  • The WebResponse that is servicing the request

Once the DownloadInfo class is instantiated, the data is downloaded in 1KB chunks and written to the disk. This is the default block size and can be changed through the BlockSize property. It is this implementation that allows the download to resume if it is cancelled or interrupted.

While this implementation is functional, it does prevent anyone from using the class who is behind a proxy or who requires authentication to access the requested URL. In order to support these scenarios, the FileDownloader class provides both a Proxy property that accepts an IWebProxy derived object and a Credentials property that accepts an ICredentials derived object. These properties are also passed on to the underlying DownloadInfo object.

Finally, the events provide progress feedback. The WebClient class in .NET 2.0 has asynchronous download methods that provide just such events. These methods are serviced by the DownloadCompletedEventArgs and DownloadProgressChangedEventArgs EventArgs derived classes. Unfortunately, both of these classes have internal constructors and are new in .NET 2.0, so I wasn't able to make use of them. Instead, I created a new triplet set of EventArgs derived classes to handle the three events that are exposed by the FileDownloader class. These events are:

  • public event EventHandler<FileDownloadCompletedEventArgs> DownloadCompleted
  • public event EventHandler<FileDownloadProgressChangedEventArgs> DownloadProgressChanged;
  • public event EventHandler<FileDownloadStatusChangedEventArgs> DownloadStatusChanged;

These events are raised during the actual file download to provide the caller with status information (DownloadStatusChanged), progress information (DownloadProgressChanged) and completion information (DownloadCompleted). A complete example looks like this:

private void DoDownload()
{
    Uri fileUrl = new Uri("http://www.codeproject.com" +
        "/info/stuff/cp_bg_black1024.gif");
    string tempPath = Path.GetTempPath();
    string fileName = Path.GetFileName(fileUrl.AbsoluteUri);
    string downloadPath = Path.Combine(tempPath, fileName);

    FileDownloader downloader = new FileDownloader();
    downloader.Proxy = WebRequest.DefaultWebProxy;
    downloader.Credentials = CredentialCache.DefaultCredentials;

    downloader.DownloadCompleted += new
        EventHandler<FileDownloadCompletedEventArgs>(OnDownloadCompleted);
    downloader.DownloadProgressChanged += new
        EventHandler<FileDownloadProgressChangedEventArgs>(
        OnDownloadProgressChanged);
    downloader.DownloadStatusChanged += new
        EventHandler<FileDownloadStatusChangedEventArgs>(
        OnDownloadStatusChanged);

    // Download the requested file to the specified folder
    downloader.Download(fileUrl, tempPath);
}

private void OnDownloadCompleted(object sender,
    FileDownloadCompletedEventArgs e)
{
    // Do something when the download completes.
}

private void OnDownloadProgressChanged(object sender,
    FileDownloadProgressChangedEventArgs e)
{
    // Do something when the progress changes,
    // usually you would increment a progress bar.
}

private void OnDownloadStatusChanged(object sender,
    FileDownloadStatusChangedEventArgs e)
{
    // Do something when that status changes.
}

Here is the same example using VB.NET. This example is based on the comment [^] by CBlackburn [^].

Private Sub DoDownload()
    Dim fileUrl As Uri = New Uri("http://www.codeproject.com/" & _
        "info/stuff/cp_bg_black1024.gif")

    Dim tempPath As String = Path.GetTempPath()
    Dim fileName As String = Path.GetFileName(fileUrl.AbsoluteUri)
    Dim downloadPath As String = Path.Combine(tempPath, fileName)

    Dim downloader As FileDownloader = New FileDownloader()
    downloader.Proxy = WebRequest.DefaultWebProxy
    downloader.Credentials = CredentialCache.DefaultCredentials

    AddHandler downloader.DownloadCompleted, _
        AddressOf OnDownloadCompleted
    AddHandler downloader.DownloadProgressChanged, _
        AddressOf OnDownloadProgressChanged
    AddHandler downloader.DownloadStatusChanged, _
        AddressOf OnDownloadStatusChanged

    downloader.Download(fileUrl, tempPath)
End Sub

Private Sub OnDownloadCompleted(ByVal sender As Object, _
    ByVal e As FileDownloadCompletedEventArgs)
    ' Do something when the download completes.
End Sub

Private Sub OnDownloadProgressChanged(ByVal sender As Object, _
    ByVal e As FileDownloadProgressChangedEventArgs)
    ' Do something when the progress changes,
    ' usually you would increment a progress bar.
End Sub

Private Sub OnDownloadStatusChanged(ByVal sender As Object, _
    ByVal e As FileDownloadStatusChangedEventArgs)
    ' Do something when that status changes.
End Sub

The complete public API for the FileDownloader class is available in the documentation CHM file that is part of the download.

Points of Interest

While the FileDownloader class is available as both a .NET 2.0 and .NET 1.1 solution, only the .NET 2.0 solution has been updated to provide the asynchronous download features and other modifications listed in the revision history.

The DownloadInfo class implements the IDisposable pattern. However, the way this pattern is implemented may be different than many of you have seen before. For more information, please refer to this article: Implementing IDisposable and the Dispose Pattern Properly [^] .

Revision History

16-August-2007:

  • Added the ability to set the User-agent HTTP header.

12-August-2007:

  • Added asynchronous support
  • Added the ability to retrieve the last modified date of the file
  • Added support for Pre-Authenticating the web request
  • Added the ability to download an HTML page
  • Added the ability to overwrite the file downloaded if it already exists

11-January-2007:

  • Added a complete example in VB.NET

27-August-2006:

  • Updated source code to include an application configuration file

25-August-2006:

  • Original article

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Scott Dorman
Software Developer (Senior)
United States United States
I am a Microsoft C# MVP, author, speaker, blogger, and software developer. I also created the WP Requests and WinStore Requests sites for Windows Phone and Windows Sotre apps as well as several open source projects.

I've been involved with computers in one way or another for as long as I can remember, but started professionally in 1993. Although my primary focus right now is commercial software applications, I prefer building infrastructure components, reusable shared libraries and helping companies define, develop and automate process and code standards and guidelines.

You may also be interested in...

Comments and Discussions

 
QuestionSincronous download Pin
It's Me Mario28-Sep-12 2:33
memberIt's Me Mario28-Sep-12 2:33 
GeneralAbility to set downloaded filename Pin
TeaTime9-Mar-10 3:34
memberTeaTime9-Mar-10 3:34 
GeneralRe: Ability to set downloaded filename Pin
Scott Dorman9-Mar-10 3:42
memberScott Dorman9-Mar-10 3:42 
GeneralSlow Downloading Speed Pin
Meganight12-Feb-10 2:55
memberMeganight12-Feb-10 2:55 
Questionwhere the files? Pin
ngjunda10-Feb-09 14:18
memberngjunda10-Feb-09 14:18 
GeneralGood One Pin
sathishC56-Apr-08 19:38
membersathishC56-Apr-08 19:38 
General[Message Deleted] Pin
babaa27-Feb-08 11:41
memberbabaa27-Feb-08 11:41 
GeneralRe: Broken Link Pin
Scott Dorman27-Feb-08 11:47
mvpScott Dorman27-Feb-08 11:47 
QuestionCancel a download?? Pin
MarkGMcM3-Dec-07 17:14
memberMarkGMcM3-Dec-07 17:14 
GeneralRe: Cancel a download?? Pin
Scott Dorman30-Dec-07 3:51
memberScott Dorman30-Dec-07 3:51 
GeneralRe: Cancel a download?? Pin
Alex Poon12-Mar-08 17:22
memberAlex Poon12-Mar-08 17:22 
GeneralRe: Cancel a download?? Pin
Scott Dorman12-Mar-08 18:17
mvpScott Dorman12-Mar-08 18:17 
AnswerRe: Cancel a download?? [modified] Pin
srtravis1-Apr-08 12:51
membersrtravis1-Apr-08 12:51 
GeneralRe: Cancel a download?? Pin
Scott Dorman1-Apr-08 14:07
mvpScott Dorman1-Apr-08 14:07 
QuestionDownload speed Pin
Yuriy Opryshko30-Oct-07 7:04
memberYuriy Opryshko30-Oct-07 7:04 
GeneralRe: Download speed Pin
Scott Dorman30-Dec-07 3:50
memberScott Dorman30-Dec-07 3:50 
GeneralUsing in ASP.net Web Apps. Pin
kirubasankar21-Sep-07 10:21
memberkirubasankar21-Sep-07 10:21 
GeneralRe: Using in ASP.net Web Apps. Pin
Scott Dorman22-Oct-07 14:54
memberScott Dorman22-Oct-07 14:54 
QuestionSQL Server integration? Pin
SAinCA20-Aug-07 14:10
memberSAinCA20-Aug-07 14:10 
AnswerRe: SQL Server integration? Pin
Scott Dorman20-Aug-07 15:01
memberScott Dorman20-Aug-07 15:01 
GeneralRe: SQL Server integration? Pin
SAinCA21-Aug-07 6:59
memberSAinCA21-Aug-07 6:59 
GeneralRe: SQL Server integration? Pin
Scott Dorman21-Aug-07 9:15
memberScott Dorman21-Aug-07 9:15 
GeneralVery nice Pin
Dmitry Khudorozhkov17-Aug-07 3:42
memberDmitry Khudorozhkov17-Aug-07 3:42 
GeneralRe: Very nice Pin
Scott Dorman17-Aug-07 3:50
memberScott Dorman17-Aug-07 3:50 
GeneralDownloading Unknown Files Pin
tempsh10-Jul-07 23:06
membertempsh10-Jul-07 23:06 
GeneralRe: Downloading Unknown Files Pin
Scott Dorman11-Jul-07 2:59
memberScott Dorman11-Jul-07 2:59 
GeneralRe: Downloading Unknown Files Pin
The_Mega_ZZTer17-Aug-07 4:54
memberThe_Mega_ZZTer17-Aug-07 4:54 
GeneralRe: Downloading Unknown Files Pin
tomseyes4-Aug-09 17:41
membertomseyes4-Aug-09 17:41 
GeneralCopyright Pin
caribiksun25-Jun-07 1:39
membercaribiksun25-Jun-07 1:39 
GeneralRe: Copyright Pin
Scott Dorman25-Jun-07 3:14
memberScott Dorman25-Jun-07 3:14 
GeneralRe: Copyright Pin
caribiksun25-Jun-07 3:43
membercaribiksun25-Jun-07 3:43 
QuestionWhat about Browser-Only websites? Pin
|\/| |\/| Saffari13-Jun-07 4:59
member|\/| |\/| Saffari13-Jun-07 4:59 
AnswerRe: What about Browser-Only websites? Pin
Scott Dorman13-Jun-07 5:17
memberScott Dorman13-Jun-07 5:17 
AnswerRe: What about Browser-Only websites? Pin
Scott Dorman16-Aug-07 13:15
memberScott Dorman16-Aug-07 13:15 
QuestionIllegal Characters in Path Error Pin
fossx4-Jun-07 12:00
memberfossx4-Jun-07 12:00 
AnswerRe: Illegal Characters in Path Error Pin
Scott Dorman12-Jun-07 4:18
memberScott Dorman12-Jun-07 4:18 
GeneralThanks!! + About credentials Pin
philippe dykmans8-May-07 10:02
memberphilippe dykmans8-May-07 10:02 
GeneralRe: Thanks!! + About credentials Pin
Scott Dorman8-May-07 14:24
memberScott Dorman8-May-07 14:24 
GeneralLast Modified Date Pin
Matt10912-Apr-07 4:47
memberMatt10912-Apr-07 4:47 
GeneralRe: Last Modified Date Pin
Scott Dorman12-Apr-07 4:51
memberScott Dorman12-Apr-07 4:51 
GeneralRe: Last Modified Date Pin
Matt10916-Jul-07 6:46
memberMatt10916-Jul-07 6:46 
GeneralRe: Last Modified Date Pin
Scott Dorman16-Aug-07 13:17
memberScott Dorman16-Aug-07 13:17 
GeneralDude, you rock!! Pin
TarlN14-Mar-07 10:23
memberTarlN14-Mar-07 10:23 
GeneralRe: Dude, you rock!! Pin
Scott Dorman17-Mar-07 4:00
memberScott Dorman17-Mar-07 4:00 
GeneralDownloading same file again not working... Pin
roel_v8-Mar-07 23:37
memberroel_v8-Mar-07 23:37 
GeneralRe: Downloading same file again not working... Pin
Scott Dorman9-Mar-07 3:48
memberScott Dorman9-Mar-07 3:48 
GeneralRe: Downloading same file again not working... Pin
rvlemmings15-Mar-07 6:57
memberrvlemmings15-Mar-07 6:57 
GeneralRe: Downloading same file again not working... Pin
Scott Dorman17-Mar-07 3:58
memberScott Dorman17-Mar-07 3:58 
GeneralRe: Downloading same file again not working... Pin
Scott Dorman16-Aug-07 13:17
memberScott Dorman16-Aug-07 13:17 
GeneralHad to add Pre-Authenticate ability Pin
regal30521-Feb-07 11:04
memberregal30521-Feb-07 11:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150728.1 | Last Updated 17 Aug 2007
Article Copyright 2006 by Scott Dorman
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid