7
\$\begingroup\$

All classes on GitHub repo

This is the code for downloading files from a FTP-server running Mozilla Fileserver.

FtpItem is the interface for the two classes FtpFile and FtpFolder; FtpFile represents a file on the server and FtpFolder represents a Folder directory on the server.

FtpUser might be better named FtpHandler or something, it was made to avoid having global variables in the WinForms UI class together with non-UI specific logic.

TransferProgress is a class which is passed from FtpItem and FtpFile through events to update the progress of a download or tell the UI when a directory is downloaded and ready to be shown in the listbox.

FtpFileList is the name of the listbox in which FtpItems are shown to the user. Debuglist currently prints information about what's happening behind the scenes to avoid stepping through to check non-critical logic.

Right now it seems like only one task can be run in the background at any time, i.e it's not possible to change to a directory that's not currently downloaded while a file is transferring; I'm currently working on fixing this.


FtpItem Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FtpLibrary
{
public interface FtpItem
{

    string Name { get; }
    string Path { get; }
    int FileSize { get; }
    SortedList<string, FtpItem> List { get; }
    void Download(string s, string t, string p);
    FtpItem PreviousItem { get; }
    int Count { get; }
    event Action<TransferProgress> DownloadProgress;

}
}

FtpFolder Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using System.Diagnostics;

namespace FtpLibrary
{
public class FtpFolder : FtpItem
{
    private static int _folderAmount = 0;
    private string _folderName;
    private string _folderPath;
    private FtpItem _parent;
    private SortedList<string, FtpItem> _folderList;
    public event Action<TransferProgress> DownloadProgress;

    public FtpFolder(string foldername, string folderpath, FtpItem parent)
    {
        _folderName = foldername;
        _folderPath = folderpath;
        _parent = parent;
        _folderList = new SortedList<string, FtpItem>();
        _folderAmount += 1;
    }

    public string Name { get { return _folderName; } }
    public string Path { get { return _folderPath; } }
    public SortedList<string, FtpItem> List { get { return _folderList; } }
    public int FileSize { get { return 0; } }
    public FtpItem PreviousItem { get { return _parent; } }
    public void Download(string _username, string _password, string _savePath=null)
    {
        var ellapsedTime = Stopwatch.StartNew();

        FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri(this.Path));


        request.Credentials = new NetworkCredential(_username, _password);
        request.Proxy = null;
        request.UseBinary = true;
        request.EnableSsl = true;

        ServicePoint sp;
        sp = request.ServicePoint;
        sp.ConnectionLimit = 1;
        ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };


            request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
            FtpWebResponse response = (FtpWebResponse)request.GetResponse();

            using (Stream responseStream = response.GetResponseStream())
            using (StreamReader reader = new StreamReader(responseStream))

            {
                SortedList<string, FtpItem> updateList = new SortedList<string, FtpItem>();

                FtpFolder tempFolder = new FtpFolder(" /cd ..", Path, this);

                updateList.Add(tempFolder.Name, tempFolder);

                while (!reader.EndOfStream)
                {
                    string ListDetails = reader.ReadLine();
                    var listarray = ListDetails.Split(new char[] { ' ' }, 9, StringSplitOptions.RemoveEmptyEntries);

                    if (listarray.ElementAt(4) == "0")
                    {
                        tempFolder = new FtpFolder(listarray.ElementAt(8), Path + listarray.ElementAt(8) + '/', this);
                        updateList.Add(tempFolder.Name, tempFolder);
                    }
                    else
                    {
                        FtpFile tempFile = new FtpFile(listarray.ElementAt(8), listarray.ElementAt(4), Path + listarray.ElementAt(8));
                        updateList.Add(tempFile.Name, tempFile);
                    }
                }
                responseStream.Close();
                response.Close();
                reader.Close();
                ellapsedTime.Stop();
                RefreshList(updateList);


            TransferProgress progress = new TransferProgress(0, 0);
            progress.FileSize = FileSize;
            progress.Complete = true;
            progress.EllapsedTime = (int)ellapsedTime.ElapsedMilliseconds;
            progress.Message = $"The FileSize is: {FileSize} and The name is: {Name}";

            OnDownloadProgress(progress);
        }
    }

    private void RefreshList(SortedList<string, FtpItem> updateList)
    {

        if (_folderList.Count == 0)
        {
            _folderList = updateList;
        }
        else
        {

            SortedList<string, FtpItem> removeList = new SortedList<string, FtpItem>();

            foreach (var i in _folderList)
            {
                if (!updateList.ContainsKey(i.Key))
                {
                    removeList.Add(i.Key, i.Value);
                }
            }

            foreach (var i in removeList) // removes deleted items
            {
                _folderList.Remove(i.Key);
            }

            foreach (var i in updateList)
            {
                if (!_folderList.ContainsKey(i.Key)) // check if any items have been added to the server
                {
                    _folderList.Add(i.Key, i.Value);
                }
            }

        }
    }

    private void OnDownloadProgress(TransferProgress progress)
    {
        var update = DownloadProgress;
        if (update != null)
        {
            update(progress);
        }
    }
    public int Count { get { return _folderAmount; } }


    ~FtpFolder() { _folderAmount--; }
}
}

FtpFile Class

using System;
using System.Collections.Generic;
using System.Net;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using System.Diagnostics;


namespace FtpLibrary
{
public class FtpFile : FtpItem
{
    private string _fileName;
    private int _fileSize;
    private string _filePath;
    private static int _fileAmount = 0;
    public event Action<TransferProgress> DownloadProgress;

    public FtpFile(string filename, string filesize, string filepath)
    {
        _fileName = filename;
        _fileSize = Int32.Parse(filesize);
        _filePath = filepath;
        _fileAmount += 1;
    }
    public string Name { get { return _fileName; } }
    public string Path { get { return _filePath; } }
    public int FileSize { get { return _fileSize; } }
    public SortedList<string, FtpItem> List { get { return null; } }
    public void Download(string _username, string _password, string _savePath = null)
    {
        FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri(this.Path));
        request.Credentials = new NetworkCredential(_username, _password);
        request.Proxy = null;
        request.UseBinary = true;
        request.EnableSsl = true;

        ServicePoint sp;
        sp = request.ServicePoint;
        sp.ConnectionLimit = 1;
        ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
        request.Method = WebRequestMethods.Ftp.DownloadFile;

        FileStream newFile;

        FileInfo file = new FileInfo($"{_savePath}{this.Name}");

            if (File.Exists($"{_savePath}{this.Name}"))
            {
                request.ContentOffset = file.Length;
                newFile = new FileStream($"{_savePath}{this.Name}", FileMode.Append, FileAccess.Write);
            }

            else
            {

            newFile = new FileStream($"{_savePath}{this.Name}", FileMode.Create, FileAccess.Write);
        }

        using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
        using (Stream downloadStream = response.GetResponseStream())
        using (newFile)
        {
            byte[] buffer = new byte[128 * 1024];
            int read;

            var ellapsedTime = Stopwatch.StartNew();
            TransferProgress progress = new TransferProgress(0, (int)newFile.Length);
            progress.FileSize = FileSize;

            while ((read = downloadStream.Read(buffer, 0, buffer.Length)) > 0)
            {
                newFile.Write(buffer, 0, read);

                progress.EllapsedTime = (int)ellapsedTime.ElapsedMilliseconds;
                progress.TotalTransfered = (int)newFile.Length;
                progress.Message = $"The FileSize is: {FileSize} and The name is: {Name}";

                OnDownloadProgress(progress);

            }

            ellapsedTime.Stop();
            newFile.Close();
            downloadStream.Close();
            response.Close();
        }
    }

    public FtpItem PreviousItem { get { return this; } }
    public int Count { get { return _fileAmount; } }

   private void OnDownloadProgress(TransferProgress progress)
    {
        var update = DownloadProgress;
        if(update != null)
        {
            update(progress);
        }
    }
    ~FtpFile() { _fileAmount--; }


  }

  }

FtpUser Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;

namespace FtpLibrary
{
public class FtpUser
{
    private string _userName;
    private string _password;
    private string _serverAdress;
    private string _savePath;
    private FtpItem _serverObject;
    private FtpWebRequest _ftpWebRequest;
    private FtpWebResponse _ftpWebResponse;
    private ServicePoint _servicePoint;
    private string _errorMessage;
    private bool _verified = false;
    public event Action<TransferProgress> TaskEvent;

    private bool Verified { get { return _verified; } set { _verified = value; } }
    public string UserName { get { return _userName; } set { _userName = value; } }
    public string Password { get { return _password; } set { _password = value; } }
    public string SavePath { get { return _savePath; } set { _savePath = value; } }
    public bool IsVerified { get { return _verified; } }
    public string ServerAdress { get { return _serverAdress; } set { _serverAdress = value; } }
    public string ErrorMessage { get { return _errorMessage; } set { _errorMessage = value; } }
    public FtpItem ServerObject { get { return _serverObject; } set { _serverObject = value; } }
    public FtpWebRequest Request { get { return _ftpWebRequest; } set { _ftpWebRequest = value; } }
    public FtpWebResponse Response { get { return _ftpWebResponse; } set { _ftpWebResponse = value; } }

    public bool VerifyUser()
    {
        if (CreateRequest() && CreateResponse())
        {
            _verified = true;
            _serverObject = new FtpFolder("root", _serverAdress, null);
            DownloadSelected(ServerObject);
            return _verified;
        }
        else
        {
            return _verified;
        }
    }

    private bool CreateRequest(int Connections = 1)
    {
        if (!CreateUri())
        {
            return false;
        }
        else
        {
            Request.Credentials = new NetworkCredential(UserName, Password);
            Request.Proxy = null;
            Request.UseBinary = true;
            Request.EnableSsl = true;

            _servicePoint = Request.ServicePoint;
            _servicePoint.ConnectionLimit = Connections;
            ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
            Request.Method = WebRequestMethods.Ftp.PrintWorkingDirectory;

            return true;
        }


    }

    private bool CreateResponse()
    {
        try
        {
            Response = (FtpWebResponse)Request.GetResponse();
            return true;
        }
        catch (WebException e)
        {
            ErrorMessage = $"CreateResponse: { e.Message}";
            return false;
        }
    }

    private bool CreateUri()
    {
        try
        {
            _ftpWebRequest = (FtpWebRequest)WebRequest.Create(new Uri(ServerAdress));
        }
        catch (UriFormatException e)
        {
            ErrorMessage = e.Message;
            return false;
        }
        return true;
    }

    public void PreviousFolder()
    {
        if (ServerObject != null)
        {
            ServerObject = ServerObject.PreviousItem;
        }

    }

    public bool ChangeFolder(string folder)
    {
        if (ServerObject != null && IsFolder(ServerObject.List[folder]))
        {
            ServerObject = ServerObject.List[folder];


            if (ServerObject.List.Count == 0)
            {
                DownloadSelected(ServerObject);
            }
            else
            {
                TransferProgress progress = new TransferProgress(0, 0);
                progress.Complete = true;
                FtpItem_TaskEvent(progress);
            }
            return true;
        }

        return false;
    }

    public void DownloadFile(string file)
    {
        DownloadSelected(ServerObject.List[file]);
    }

    private void DownloadSelected(FtpItem item)
    {
        if (IsVerified)
        {
            item.DownloadProgress += FtpItem_TaskEvent;
            Task t = new Task(() => item.Download(UserName, Password, SavePath));
            t.Start();
            // Task t = Task.Factory.StartNew( () => item.Download(UserName, Password));
        }
    }

    private bool IsFolder(FtpItem item)
    {
        return item.FileSize == 0;
    }

    private void FtpItem_TaskEvent(TransferProgress progress)
    {
        var update = TaskEvent;
        if (update != null)
        {
            update(progress);
        }
    }
}
}

TransferProgress Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FtpLibrary
{
public class TransferProgress
{

    private int _ellapsedTime;
    private int _totalTransfered;
    private int _fileSize;
    private static int _count = 0;
    private bool _completed = false;
    private string _message;
    public TransferProgress(int ellapsedTime, int totalTransferred)
    {
        _ellapsedTime = ellapsedTime;
        _totalTransfered = totalTransferred;
        _count++;
    }
    public int EllapsedTime {  get { return _ellapsedTime; } set { _ellapsedTime = value; } }
    public int TotalTransfered { get { return _totalTransfered; } set { _totalTransfered = value; } }
    public int FileSize { get { return _fileSize; } set { _fileSize = value; } }
    public bool Complete {  get { return _completed; } set { _completed = value; } }
    public int Count {  get { return _count; } set { _count++; } }
    public int PercentDone { get { return (int)((((float)TotalTransfered) / ((float)FileSize)) * 100); } }
    public string Message {  get { return _message; } set { _message = value; } }
    public int Seconds()
    {
        return (((FileSize - TotalTransfered) / (TotalTransfered / EllapsedTime)) / 1000) % 60;
    }
    public int Minutes()
    {
        return (((FileSize - TotalTransfered) / (TotalTransfered / EllapsedTime)) / 1000) / 60;
    }
    public string TransferSpeed()
    {
        if ((TotalTransfered / EllapsedTime) <= 1000)
        {
            return $"{TotalTransfered / EllapsedTime} kb/s ";
        }
        else
        {
            return $"{ (TotalTransfered / EllapsedTime) / 1000} + Mb/s ";
        }
    }


}
}

WinForms UI

This is mostly to show how i use Events to update the Listbox and progressbar while keeping it thread safe.

using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using FtpLibrary;
using System.Diagnostics;
using System.Collections.Generic;
using System.IO;

namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
    private FtpUser currentUser;

    public Form1()
    {
        InitializeComponent();

        ftpfileList.MouseDoubleClick += FtpfileList_MouseDoubleClick;
        SavePath.Text = $"C:/Users/{Environment.UserName}/Ftp";

        if (!Directory.Exists($"C:/Users/{Environment.UserName}/Ftp"))
        {
            Directory.CreateDirectory($"C:/Users/{Environment.UserName}/Ftp");
        }

    }

    private void FtpfileList_MouseDoubleClick(object sender, MouseEventArgs e)
    {
        try
        {
            UiListChange(ftpfileList.GetItemText(ftpfileList.SelectedItem).Substring(0, ftpfileList.GetItemText(ftpfileList.SelectedItem).IndexOf(" , Size: ")));
        }
        catch (System.ArgumentOutOfRangeException ex)
        {
            debugList.Items.Add(ex.Message);
        }

    }

    private void UiListChange(string _currentFtpItem)
    {
        if (_currentFtpItem == " /cd ..")
        {
            currentUser.PreviousFolder();
            PrintDirectory(currentUser.ServerObject);
        }
        else if (currentUser.ChangeFolder(_currentFtpItem))
        {

        }
        else // Time to download a file
        {
            currentUser.DownloadFile(_currentFtpItem);
        }
    }

    private void Connect_Click(object sender, EventArgs e) // init a session
    {
        if (Connect.Text == "Connect")
        {

            currentUser = new FtpUser();
            currentUser.UserName = UserName.Text;
            currentUser.Password = Password.Text;
            currentUser.ServerAdress = $"ftp://{Adress.Text}/";
            currentUser.SavePath = $"C:/Users/{Environment.UserName}/Ftp/";
            currentUser.TaskEvent += FtpItem_ProgressChanged;

            if (currentUser.VerifyUser())
            {
                Connect.Text = "Refresh";
            }
            else
            {
                Connect.Text = "Connect";
                MessageBox.Show(currentUser.ErrorMessage);
            }
        }
    }

    private void PrintDirectory(FtpItem item)
    {

        ftpfileList.Items.Clear();

        debugList.Items.Clear();


        foreach (var t in item.List)
        {
            ftpfileList.Items.Add(t.Value.Name + " , Size: " + t.Value.FileSize + " Byte");
        }
    }

    private void FtpItem_ProgressChanged(TransferProgress progress)
    {
        if (progress.FileSize == 0)
        {
            if (progress.Complete == true)
            {
                if (ftpfileList.InvokeRequired)
                {
                    ftpfileList.Invoke(new Action<TransferProgress>(FtpItem_ProgressChanged), new object[] { progress });
                }
                else
                {
                    PrintDirectory(currentUser.ServerObject);
                    debugList.Items.Add($"Operation took: {progress.EllapsedTime} MilliSeconds");
                    if (progress.Message != null)
                    {
                        debugList.Items.Add(progress.Message);
                    }
                }
            }
        }

        else
        {
            if (progressBar1.InvokeRequired)
            {
                progressBar1.Invoke(new Action<TransferProgress>(FtpItem_ProgressChanged), new Object[] { progress });
            }
            else
            {
                if (progress.TotalTransfered != 0)
                {
                    SpeedLabel.Text = $"{progress.PercentDone} % Complete, Speed: {progress.TransferSpeed()}\n Time Left: {progress.Minutes()} Minutes & {progress.Seconds()} seconds";
                    progressBar1.Value = progress.PercentDone;
                    debugList.Items.Add(progress.Message);
                }
                if (progressBar1.Value == 100)
                {
                    progressBar1.Value = 0;
                    debugList.Items.Clear();
                    SpeedLabel.Text = "Download Complete";
                }
            }

        }
    }

    private void OpenFtpFolder_Click(object sender, EventArgs e)
    {
        if (!Directory.Exists($"C:/Users/{Environment.UserName}/Ftp"))
        {
            Directory.CreateDirectory($"C:/Users/{Environment.UserName}/Ftp");
        }
        System.Diagnostics.Process.Start($"C:/Users/{Environment.UserName}/Ftp");
    }

    private void CancelDownload_Click(object sender, EventArgs e)
    {

    }

    private void ProgressLabel_Click(object sender, EventArgs e)
    {

    }
}
}
\$\endgroup\$

3 Answers 3

7
\$\begingroup\$
public interface FtpItem

By convention, interface names in .net start with a capital i, so the expected name for that type would be IFtpItem.

The interface has quite a few members, which points toward too many responsibilities.

In particular, the SortedList<string, FtpItem> List { get; } member smells.

...and the implementation confirms the doubt:

public SortedList<string, FtpItem> List { get { return null; } }

The interface is trying to be too many things at once.

I'll leave the rest of the FTP code to other reviewers, and focus more on the client WinForms code.


namespace WindowsFormsApplication2

Really? This could have been WinFormsFtpClient or something... But moving on...

public Form1()
{
    InitializeComponent();

    ftpfileList.MouseDoubleClick += FtpfileList_MouseDoubleClick;
    SavePath.Text = $"C:/Users/{Environment.UserName}/Ftp";

    if (!Directory.Exists($"C:/Users/{Environment.UserName}/Ftp"))
    {
        Directory.CreateDirectory($"C:/Users/{Environment.UserName}/Ftp");
    }

}

This Form1 class should be the application's MainWindow or MainForm, or FtpClientForm ...pretty much anything but Form1.

But enough nitpicking over naming. That constructor is doing too much work. You may not realize, but the Visual Studio designer is calling that code - it's by running InitializeComponent that the designer knows what controls to instantiate, where to put them, how they're named, and everything else the designer knows about the controls on that form, it knows by running that InitializeComponent method, which is generated code that you can find in the other "half" of the partial class.

By creating a directory in the form's constructor, you're not only executing I/O code in a constructor - you're running I/O code at design time, in the WinForms designer. This is what your constructor should look like:

public Form1()
{
    InitializeComponent();
    ftpfileList.MouseDoubleClick += FtpfileList_MouseDoubleClick;
}

Everything else doesn't belong there. Actually, I/O doesn't belong in the UI at all.

There's a name for the pattern going on here: Smart UI - great for prototyping, not-so-great for scalability and testability. The FTP library doesn't contain application logic: your form does. You could extract the application logic into its own class, and implement some Model-View-Presenter pattern, leaving the "view" (/form) with nothing but presentation concerns to care about.


These handlers were presumably created by the designer by double-clicking the controls. Remove the handler assignation in InitializeComponent, and then remove this dead no-op code:

private void CancelDownload_Click(object sender, EventArgs e)
{

}

private void ProgressLabel_Click(object sender, EventArgs e)
{

}

I think the methods in the TransferProgress class could be implemented as properties/getters, if you ensured that none of the getters would ever throw a division by zero exception (because getters should never throw). It's not clear whether the PercentDone getter is immune from that exception, either.

The TransferSpeed method is working too hard, performing the same division at least twice:

public string TransferSpeed()
{
    if ((TotalTransfered / EllapsedTime) <= 1000)
    {
        return $"{TotalTransfered / EllapsedTime} kb/s ";
    }
    else
    {
        return $"{ (TotalTransfered / EllapsedTime) / 1000} + Mb/s ";
    }
}

Do it once, and reuse the result in the string interpolations.

Ellapsed is actually spelled Elapsed, but that isn't the worst problem with the naming of int _ellapsedTime - is that seconds? milliseconds? minutes? hours? years? who knows... The framework has a type dedicated to represent a time interval: System.TimeSpan. Use it!

Same goes for totalTransfered: it's not clear what the unit of measure is.

\$\endgroup\$
0
3
\$\begingroup\$
private int _ellapsedTime;
public int EllapsedTime {  get { return _ellapsedTime; } set { _ellapsedTime = value; } }

You can simplify this down to public int EllapsedTime { get; set; }. This is known as an auto-implemented property, and will automatically create and manage the backing field for you. Minor nitpick: "Ellapsed" is really spelled with one "L".


This looks like a bug:

public int Count {  get { return _count; } set { _count++; } }

Pretend I have this code;

var classInstance = new TransferProgress(0, 0);  // probably not realistic arguments.
var count = classInstance.Count;  // let's say it returns '5'

classInstance.Count = 99;  // OK, I think count really returns '99' now
count = classInstance.Count;  // Count returns '6'?

classInstance.Count = 0;  // reset the value back to '0'
count = classInstance.Count;  // Count returns '7'?

One potential fix for this is to make the setter private (private set {}), so only the class itself can modify it. This does not remove the bug-like behavior, although the setter probably should be private anyway. The other option is the remove the setter entirely and let the internal class directly modify the backing field. I would probably go this route.


if (CreateRequest() && CreateResponse())
{
    _verified = true;
    _serverObject = new FtpFolder("root", _serverAdress, null);
    DownloadSelected(ServerObject);
    return _verified;
}

You can assign a value to ServerObject directly through your setter, why are you bypassing the setter and modifying the backing field? This is another excellent place to use an auto-implemented property.

\$\endgroup\$
2
  • \$\begingroup\$ My god I had missed that weird non-standard setter that doesn't use its value parameter. Nice review! \$\endgroup\$ Dec 19, 2015 at 21:21
  • \$\begingroup\$ I also discovered this error in the RefreshList() of FtpFolder, since I changed to auto implementation the errors are no more. \$\endgroup\$
    – A.J
    Dec 20, 2015 at 17:33
3
\$\begingroup\$

Regarding the interface FtpItem, as Mats Mug pointed out, should be renamed to IFtpItem, many of the methods and setters can be broken out of the FtpFile and FtpFolder classes to a Base FtpItem class which both of the former classes can inherit from.

Togheter with auto implementation which Hosch250 pointed out, would make it impossible to assign to a variable instead of using the getter/setter somewhere in the code.

The code for the FtpItem class can be rewritten with whats have been pointed out to...

public interface IFtpItem
{
    string Name { get; set; }
    string Path { get; set; }
    long FileSize { get; set; }
}

Which the base class FtpItem inherit from. Servicepoint is what decide how many connections which can be open at once, the default is 2 connections, even if a new Servicepoint is created, the connection limit will still be limited to the first Servicepoint created, so a new servicepoint with 10 connections will be blocked by an old connection with 2 or less connections. The creation of the request can also be ripped out and added to the base FtpItem class.

public class FtpItem : IFtpItem
{
    public event Action<TransferProgress> DownloadProgress;

    public FtpItem(string fileName, string fileSize, string filePath)
    {
        Name = fileName;
        FileSize = long.Parse(fileSize);
        Path = filePath;
    }

    public string Path { get; set; }
    public string Name { get; set; }
    public long FileSize { get; set; }
    public FtpWebRequest CreateRequest(string _username, string _password)
    {
        FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri(Path));


        request.Credentials = new NetworkCredential(_username, _password);
        request.Proxy = null;
        request.UseBinary = true;
        request.EnableSsl = true;


        ServicePoint sp = request.ServicePoint;
        sp.ConnectionLimit = 10;
        ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

        return request;
    }

    public void OnDownloadProgress(TransferProgress progress)
    {
        var update = DownloadProgress;
        if (update != null)
        {
            update(progress);
        }
    }
}

Then let FtpFile and FtpFolder inherit from FtpItem...

FtpFolder

public class FtpFolder : FtpItem
{
   public FtpFolder(string filename, string fileSize, string filePath, IFtpItem parent)
        : base(filename, fileSize, filePath)
       {
         Parent = parent;
         List = new SortedList<string, IFtpItem>();
       }

    public SortedList<string, IFtpItem> List { get; set; }
    public IFtpItem Parent { get; set; }

     public void Download(string userName, string password)
     {
     //Code Here
     }
     private void RefreshList(SortedList<string, IFtpItem> updateList)
     {
     //Code Here
     }
}

FtpFile

 public class FtpFile : FtpItem
{
    public FtpFile(string filename,string fileSize, string filePath)
        : base(filename, fileSize, filePath)
    {


    }
    public CancellationTokenSource CancelFileDownload { get; set; }
    public void Download(string userName, string password)
     {
     //Code Here
     }
}

To Use the same List for both FtpFile and FtpFolder, typecast these when needed, i.e

Some changed code from FtpUser.cs

else if (ChangeFolder(selectedItem))
            {
                folder = ServerObject as FtpFolder;
                return folder.List;
            }
            else if (folder.List[selectedItem].FileSize > 0)
            {
                DownloadFile(folder.List[selectedItem] as FtpFile);
                return folder.List;
            }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.