Creating FTP File Downloader Application With Background Worker

What is BackgroundWorker ?  

By default, each time your application executes a piece of code, this code is run on the same thread as the application itself. This means that while this code is running, nothing else happens inside of your application, including the updating of your UI.

This is quite a surprise to people who are new to Windows programming, when they first do something that takes more than a second and realize that their application actually hangs while doing so. The result is a lot of frustrated forum posts from people who are trying to run a lengthy process while updating a progress bar, only to realize that the progress bar is not updated until the process is done running.

The solution to all of this is the use of multiple threads, and while C# makes this quite easy to do, multi-threading comes with a LOT of pitfalls, and for a lot of people, they are just not that comprehensible. This is where the BackgroundWorker comes into play - it makes it simple, easy and fast to work with an extra thread in your Application.

Step 1

Open Visual Studio -> select File -> New Project

Here, you will be getting one pop-up as sown below from that select Visual C# -> Windows ->WPF Application template.


Give the name as FileDownloader (my Ex) and press OK button

Step 2

Now, you can see one Window (MainWindow), design that Window, as shown below.


Design Code(XAML)

  1. <Window x:Class="FileDownloader.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:FileDownloader" mc:Ignorable="d" Title="File Downloader" Height="250" Width="525" WindowStyle="SingleBorderWindow" WindowStartupLocation="CenterScreen" ResizeMode="NoResize">  
  2.     <Grid>  
  3.         <Label Content="Copy and Paste the URL to download" HorizontalAlignment="Left" Margin="25,47,0,0" VerticalAlignment="Top" Width="436" x:Name="lblStatus" Foreground="Black" FontSize="14" FontWeight="Normal" />  
  4.         <ProgressBar HorizontalAlignment="Left" Height="30" Margin="25,81,0,0" VerticalAlignment="Top" Width="469" x:Name="progressBar1" />  
  5.         <TextBox HorizontalAlignment="Left" Margin="24,81,0,0" VerticalAlignment="Top" Width="470" x:Name="txtUrl" Foreground="Black" FontSize="14" FontWeight="Normal" Height="31" />  
  6.         <Label Content="Downloaded" HorizontalAlignment="Left" Margin="26,118,0,0" VerticalAlignment="Top" Width="311" x:Name="lblProgress" Height="32" Foreground="Black" FontSize="14" FontWeight="Normal" />  
  7.         <Button HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Cursor="Hand" Margin="418,120,0,0" Content="Cancel" x:Name="btnCancel" Foreground="White" Background="Red" Click="btnCancel_Click" Height="28" RenderTransformOrigin="-2.013,-5.682" />  
  8.         <Button HorizontalAlignment="Left" VerticalAlignment="Top" Cursor="Hand" IsDefault="True" Width="75" Margin="418,120,0,0" x:Name="btnDownload" Click="btnDownload_Click" Content="Download" Background="Blue" Foreground="White" Height="28" /> </Grid>  
  9. </Window>  

Step 3

Now, design is completed. Let’s do some coding, so press F7 or go to code view.

  • First, we will hide cancel button and give focus to URL textbox when loading screen, as shown below.
    1. public MainWindow() {  
    2.     InitializeComponent();  
    3.     txtUrl.Focus();  
    4.     btnCancel.Visibility = Visibility.Hidden;  
    5.     lblProgress.Content = "";  
    6. }  
  • Now, we will do the code for download button to download the file from the given URL in the textbox, as shown below.
    1. private void btnDownload_Click(object sender, RoutedEventArgs e) {  
    2.     if (txtUrl.Text == string.Empty) //checking Is URL empty  
    3.     {  
    4.         MessageBox.Show("Copy and Past the URL into the Text Box to download""URL", MessageBoxButton.OK, MessageBoxImage.Information);  
    5.         txtUrl.Focus();  
    6.         return;  
    7.     }  
    8.     txtUrl.Visibility = Visibility.Hidden;  
    9.     btnDownload.Visibility = Visibility.Hidden;  
    10.     btnCancel.Visibility = Visibility.Visible;  
    11.     progressBar1.Visibility = Visibility.Visible;  
    12.     progressBar1.Value = 0; //Initializing progress value to 0  

Step 4

While downloading a file, it will take some time to download. By this, if we do direct code to download without using thread, the application will not respond until the download finishes, as this download is a long process, so we can use Background worker processor to handle such situation. Using this, we can control the application even if it is in long process and we can show the progress as well. To do this, first add namespace, as shown below. 

  1. using System.ComponentModel;  

Writes the function, as shown below.

  1. Function to do the task is given below.
    1. private void worker_DoWork(object sender, DoWorkEventArgs e)  
    2.   
    3. {  
    4.   
    5. }  
  1. Function to show the progress is given below.
    1. void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) {}  
  1. Function after completing the task is given below.
    1. private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {}  

Step 5

Let’s start filing these Background worker functions, as shown below. 

  1. DoWork
    1. private void worker_DoWork(object sender, DoWorkEventArgs e) {  
    2.     try {  
    3.         FtpWebRequest request = (FtpWebRequest) FtpWebRequest.Create(new Uri(txtUrl.Text));  
    4.         request.Proxy = null;  
    5.         request.Method = WebRequestMethods.Ftp.GetFileSize;  
    6.         FtpWebResponse response = (FtpWebResponse) request.GetResponse();  
    7.         long size = response.ContentLength;  
    8.         response.Close();  
    9.         filesize = ConvertBytesToMegabytes(size);  
    10.         FtpWebRequest requestFileDownload = (FtpWebRequest) WebRequest.Create(txtUrl.Text);  
    11.         requestFileDownload.Method = WebRequestMethods.Ftp.GetFileSize;  
    12.         requestFileDownload.Method = WebRequestMethods.Ftp.DownloadFile;  
    13.         FtpWebResponse responseFileDownload = (FtpWebResponse) requestFileDownload.GetResponse();  
    14.         Stream responseStream = responseFileDownload.GetResponseStream();  
    15.         FileStream writeStream = new FileStream(Environment.SpecialFolder.Desktop + "File.zip", FileMode.Create);  
    16.         int Length = 1024;  
    17.         Byte[] buffer = new Byte[Length];  
    18.         int bytesRead = responseStream.Read(buffer, 0, Length);  
    19.         while (bytesRead > 0) {  
    20.             writeStream.Write(buffer, 0, bytesRead);  
    21.             bytesRead = responseStream.Read(buffer, 0, Length);  
    22.             filesizedownloaded = ConvertBytesToMegabytes(writeStream.Length);  
    23.             worker.ReportProgress(Convert.ToInt32((Convert.ToInt32(filesizedownloaded) / filesize) * 100));  
    24.         }  
    25.         responseStream.Flush();  
    26.         responseStream.Dispose();  
    27.         responseStream.Close();  
    28.         writeStream.Flush();  
    29.         writeStream.Dispose();  
    30.         writeStream.Close();  
    31.         requestFileDownload = null;  
    32.         responseFileDownload = null;  
    33.     } catch {  
    34.         MessageBox.Show("Your internet connection appears to be down or URL not found. Please check it and try again""Communications Error", MessageBoxButton.OK, MessageBoxImage.Information);  
    35.     }  
    36. }  
  1. worker_ProgressChanged
    1. void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) {  
    2.     progressBar1.Value = e.ProgressPercentage;  
    3.     lblStatus.Content = "Downloading...";  
    4.     lblProgress.Content = "Download " + filesizedownloaded.ToString("F2") + " / " + filesize.ToString("F2") + " ( " + progressBar1.Value.ToString() + " ) % Complete.";  
    5. }  
  1. worker_RunWorkerCompleted
    1. private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {  
    2.     lblStatus.Content = "Download finished";  
    3.     try {  
    4.         worker.CancelAsync();  
    5.         worker = null;  
    6.     } catch {}  
    7.     txtUrl.Text = "";  
    8.     lblStatus.Content = "Copy and Paste the URL to download";  
    9.     txtUrl.Focus();  
    10.     txtUrl.Visibility = Visibility.Visible;  
    11.     btnDownload.Visibility = Visibility.Visible;  
    12.     lblProgress.Visibility = Visibility.Hidden;  
    13. }  

Step 6

The final step is to do the download and cancel button code, as shown below. 

  1. private BackgroundWorker worker = null;  
  2. double filesizedownloaded = 0, filesize = 0;  
  3. private void btnDownload_Click(object sender, RoutedEventArgs e) {  
  4.     if (txtUrl.Text == string.Empty) //checking Is URL empty  
  5.     {  
  6.         MessageBox.Show("Copy and Past the URL into the Text Box to download""URL", MessageBoxButton.OK, MessageBoxImage.Information);  
  7.         txtUrl.Focus();  
  8.         return;  
  9.     }  
  10.     cancel = "";  
  11.     lblProgress.Visibility = Visibility.Visible;  
  12.     txtUrl.Visibility = Visibility.Hidden;  
  13.     btnDownload.Visibility = Visibility.Hidden;  
  14.     btnCancel.Visibility = Visibility.Visible;  
  15.     progressBar1.Visibility = Visibility.Visible;  
  16.     Source = txtUrl.Text;  
  17.     progressBar1.Value = 0; //Initializing progress value to 0  
  18.     if (worker == null) {  
  19.         worker = new BackgroundWorker();  
  20.         worker.DoWork += worker_DoWork;  
  21.         worker.RunWorkerCompleted += worker_RunWorkerCompleted;  
  22.         worker.ProgressChanged += worker_ProgressChanged;  
  23.         worker.WorkerReportsProgress = true;  
  24.         worker.WorkerSupportsCancellation = true;  
  25.     }  
  26.     if (worker.IsBusy != true) {  
  27.         // Start the asynchronous operation.  
  28.         worker.RunWorkerAsync();  
  29.     }  
  30. }  
  31. private void btnCancel_Click(object sender, RoutedEventArgs e) {  
  32.     cancel = "y";  
  33.     try {  
  34.         worker.CancelAsync();  
  35.         worker = null;  
  36.     } catch {}  
  37.     lblProgress.Visibility = Visibility.Hidden;  
  38.     txtUrl.Text = "";  
  39.     lblStatus.Content = "Copy and Paste the URL to download";  
  40.     txtUrl.Focus();  
  41.     txtUrl.Visibility = Visibility.Visible;  
  42.     btnCancel.Visibility = Visibility.Hidden;  
  43.     btnDownload.Visibility = Visibility.Visible;  
  44. }  

Now, we can run and check how it will work, which is shown below. 

  1. For testing, we can use ftp://speedtest.tele2.net/ link, open this link and right click on any  file, which you wanted to test and select copy link location, shown below.


  1. Paste this link to our app File Downloader Textbox, followed by clicking download now and you can see the progress without interruption or hanging, as shown below. In Destination file, I have hardcoded as E:\Test\File.zip