Senin, 17 Agustus 2015

C#/CSharp Upload file to FTP server with progress bar


Introduction

This is a simple code to upload file with progress status. This is just a code snippet for me because it's hard to find a similar one. I will be happy if you find this code useful. Any suggestion for my traditional style code will be happily accepted.

Link to Working code

Using the code

Net 3.5 framework

Minimum framework is net 3.5 (See next section for net 4.5 framework)
Create new windows Form Application project targeted for net 3.5 or later.
Add button1, progressBar1 and label1 to Form1:
Set progressbar1.Maximum to 100
Component required
System.IOSystem.Net.
To avoid UI including progressBar1 from freezing use BackgroundWorker.
Form1.cs Complete code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Windows.Forms;

namespace Simple_FTP_Upload
{
    public partial class Form1 : Form
    {
        string filePath = @"C:\fileFolder\";
        string filetoUpload = "filetoupload.7z";
        string ftpDir = "ftpDir/";
        string ftpAddress = "ftp://ftp.ftpserver.net/";
        string ftpUser = "user";
        string ftpPassword = "password";

        BackgroundWorker backgroundWorker1 = new BackgroundWorker();//look at ref 5

        public Form1()
        {
            InitializeComponent();
            backgroundWorker1.WorkerReportsProgress = true;
            backgroundWorker1.DoWork +=
                new DoWorkEventHandler(backgroundWorker1_DoWork);//look at ref 5
            backgroundWorker1.ProgressChanged +=
                new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);//look at ref 5
            backgroundWorker1.RunWorkerCompleted +=
                new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);//look at ref 5
        }

        private void button1_Click(object sender, EventArgs e)
        {
            button1.Enabled = false;
            progressBar1.Visible = true;

            if (backgroundWorker1.IsBusy != true)
            {
                // Start the asynchronous operation.
                backgroundWorker1.RunWorkerAsync();
            }               
        }

        string processFtp(BackgroundWorker worker)
        {
            string result = "";
            try
            {
                // Get the object used to communicate with the server.
                FtpWebRequest request =
                    (FtpWebRequest)WebRequest.Create(ftpAddress + ftpDir + filetoUpload);
                request.Method = WebRequestMethods.Ftp.UploadFile;

                request.Credentials = new NetworkCredential(ftpUser, ftpPassword);

                request.KeepAlive = false;//look at ref 4
                request.ReadWriteTimeout = 1000000000;//look at  4
                request.Timeout = 1000000000;//look at  4

                using (Stream requestStream = request.GetRequestStream())
                {

                    using (FileStream fs = File.OpenRead(filePath + filetoUpload))
                    {
                        byte[] b = new byte[10 * 1024];
                        int readLength = 0;
                        int sentLength = 0;
                        while ((readLength = fs.Read(b, 0, b.Length)) > 0)
                        {
                            requestStream.Write(b, 0, b.Length);
                            int percentComplete = (int)((float)(sentLength+=readLength) / 
                                                                        (float)fs.Length * 100);
                            //Update progress bar according to b.length
                            worker.ReportProgress(percentComplete);
                        }
                    }
                }

                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                response.Close();

                //Successfull sent information
                result = "Kirim Data selesai, status :" + response.StatusDescription;
            }
            catch (WebException e)
            {
                //Fail sent information
                result = "Kirim Data Gagal." +
                                    "\n Status :" + e.Message;
                if (e.Status == WebExceptionStatus.ProtocolError)
                {
                    result = result + "Status Code : " +
                        ((FtpWebResponse)e.Response).StatusCode;
                    result = result + "\nStatus Description : " +
                        ((FtpWebResponse)e.Response).StatusDescription;
                }
            }
            catch (Exception e)
            {
                result = e.Message;
            }
            return result;
        }


        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            e.Result = processFtp(worker);
        }

        // This event handler updates the progress bar. 
        private void backgroundWorker1_ProgressChanged(object sender,
            ProgressChangedEventArgs e)
        {
            this.progressBar1.Value = e.ProgressPercentage;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.label1.Text = e.Result.ToString();
            this.button1.Enabled = true;
        }

    }
}

Net 4.5 framework

Create new windows Form Application project targeted for net 4.5 or later;
Add button1, progressBar1 and label1 to Form1:
Set progressbar1.Maximum to 100
Component required
System.IO, System.Net.
Update progress bar is more simpler in net 4.5 than net 3.5 use async task so UI thread will not blocked. For more detailed you can chek this https://msdn.microsoft.com/en-us/library/hh191443.aspx
Complete code for Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Simple_Upload_to_FTP_net_4._5
{
    public partial class Form1 : Form
    {
        string filePath = @"C:\fileFolder\";
        string filetoUpload = "filetoupload.7z";
        string ftpDir = "ftpDir/";
        string ftpAddress = "ftp://ftp.ftpserver.net/";
        string ftpUser = "user";
        string ftpPassword = "password";

        public Form1()
        {
            InitializeComponent();
        }

        // Mark the event handler with async so you can use await in it. 
        private async void button1_Click(object sender, EventArgs e)
        {
            label1.Text = "Uploading";
            button1.Enabled = false;
            await processFtp();
        }

        async Task processFtp()
        {
            string result = "";
            try
            {
                // Get the object used to communicate with the server.
                FtpWebRequest request =
                    (FtpWebRequest)WebRequest.Create(ftpAddress + ftpDir + filetoUpload);
                request.Method = WebRequestMethods.Ftp.UploadFile;

                request.Credentials = new NetworkCredential(ftpUser, ftpPassword);

                request.KeepAlive = false;//look at ref 4
                request.ReadWriteTimeout = 1000000000;//look at ref 4
                request.Timeout = 1000000000;//look at ref 4

                using (Stream requestStream = request.GetRequestStream())
                {

                    using (FileStream fs = File.OpenRead(filePath + filetoUpload))
                    {
                        byte[] b = new byte[10 * 1024];
                        int readLength = 0;
                        int sentLength = 0;
                        while ((readLength = fs.Read(b, 0, b.Length)) > 0)
                        {
                            await requestStream.WriteAsync(b, 0, b.Length);
                            int percentComplete = (int)((float)(sentLength += readLength) / 
                                                                         (float)fs.Length * 100);
                            progressBar1.Value = percentComplete;
                        }
                    }
                }

                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                response.Close();

                //Successfull sent information
                result = "Kirim Data selesai, status :" + response.StatusDescription;
            }
            catch (WebException e)
            {
                //Fail sent information
                result = "Kirim Data Gagal." +
                                    "\n Status :" + e.Message;
                if (e.Status == WebExceptionStatus.ProtocolError)
                {
                    result = result + "Status Code : " +
                        ((FtpWebResponse)e.Response).StatusCode;
                    result = result + "\nStatus Description : " +
                        ((FtpWebResponse)e.Response).StatusDescription;
                }
            }
            catch (Exception e)
            {
                result = e.Message;
            }
            label1.Text = result;
            button1.Enabled = true;
        }

    }
}

References

  1. FTP example: https://msdn.microsoft.com/en-us/library/ms229715(v=vs.110).aspx
  2. Additional FTP example: http://www.codeproject.com/Tips/443588/Simple-Csharp-FTP-Class
  3. Handling HttpWebRequest error: https://msdn.microsoft.com/en-us/library/system.net.webexception.response(v=vs.110).aspx
  4. Resolve big file upload: http://stackoverflow.com/questions/1060966/big-files-uploading-webexception-the-connection-was-closed-unexpectedly
  5. Update progressbar with backgroundworker: https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

6 komentar:

  1. Thanks for you sample, which seems to work fine! BUT itcontains a bug! (4.5 version)


    while ((readLength = fs.Read(b, 0, b.Length)) > 0)
    {
    await requestStream.WriteAsync(b, 0, b.Length);

    causes that the file on the ftp server is always bigger than the original!!!

    when using:


    while ((bytesRead = fs.Read(b, 0, b.Length)) > 0)
    {
    await requestStream.WriteAsync(b, 0, bytesRead);

    The destination file has the same size as the original as it writes only the read bytes.

    BalasHapus
    Balasan
    1. add the line:
      request.UseBinary = true;
      or upload a *.zip file which is tranferred in binary mode then you will see that the destination file is bigger than the origine!!!

      Hapus
  2. add the line:
    request.UseBinary = true;
    or try to upload a *.zip file
    you will see that the destination file is bigger!!!

    BalasHapus
  3. add the line:
    request.UseBinary = true;
    or upload a *.zip file which is tranferred in binary mode and you will see that the destination file is bigger than the origine!!!

    BalasHapus
  4. Your code works!!
    Thank you Dadan

    BalasHapus
  5. Hi Dadan,
    How to show progress bar for multiple files upload from folder?

    BalasHapus