65.9K
CodeProject is changing. Read more.
Home

ASP.NET: Using SFTP/FTP in ASP.NET Projects

Jul 20, 2020

CPOL
viewsIcon

12945

downloadIcon

344

Using SFTP/FTP in ASP.NET projects

Background

In this article, we will check FTP/SFTP usages in ASP.NET projects. We are going to create an FTP/SFTP client class to connect and do operations on FTP/SFTP systems.

The operation includes:

  • Connecting/disconnecting with the server
  • Uploading/downloading files
  • Checking files/directories
  • Creating/deleting files/directories
  • And others

SFTP/FTP

Here are some common Interfaces to create some adapter classes for SFTP and FTP clients.

using System;
using System.Collections.Generic;

namespace DotNetFtpSftp
{
    public interface IFileSystem
    {
        bool FileExists(string filePath);
        bool DirectoryExists(string directoryPath);
        void CreateDirectoryIfNotExists(string directoryPath);
        void DeleteFileIfExists(string filePath);
    }

    public interface IRemoteFileSystemContext : IFileSystem, IDisposable 
    {
        bool IsConnected();
        void Connect();
        void Disconnect();

        List<string> FileNames(string directory);
        List<string> FileNames(string directory, string filePrefix, 
                               string fileSuffixOrExtension = "");

        void UploadFile(string localFilePath, string remoteFilePath);
        void DownloadFile(string localFilePath, string remoteFilePath);
    }
}

For SFTP/FTP works, we are going to use WinSCP. We can add the below code to our packages.config file or install it using NuGet.

<packages>
  <package id="WinSCP" version="5.17.6" targetFramework="net45" />
</packages>

Let's create the adapter class by implementing the interface.

using System;
using System.Collections.Generic;
using System.Linq;
using WinSCP;

namespace DotNetFtpSftp
{
    /*winscp example
     * https://winscp.net/eng/docs/library_examples
     * Local Directory:         C:\DumpFiles\file.csv (C:\\DumpFiles\\file.csv)
     * Ftp Directory(WinScp):   /ArchiveFiles/file.csv
     */
    public class FtpSftpFileContext : IRemoteFileSystemContext
    {
        public SessionOptions SessionOptions { get; }

        private Session _session;

        public FtpSftpFileContext(RemoteSystemSetting setting)
        {
            string protocolType = setting.Type;
            SessionOptions = new SessionOptions
            {
                HostName = setting.Host,
                UserName = setting.UserName,
                Password = setting.Password,
                PortNumber = setting.Port,
                Protocol = (Protocol) Enum.Parse(typeof(Protocol), protocolType),
            };
            if (new List<Protocol>(){ Protocol.Sftp }.Contains(SessionOptions.Protocol))
            {
                SessionOptions.GiveUpSecurityAndAcceptAnySshHostKey = true;
            }
        }

        public void Connect()
        {
            _session = new Session();
            _session.Open(SessionOptions);
        }

        public List<string> FileNames(string directory)
        {
            var files = _session.EnumerateRemoteFiles
                        (directory, "", EnumerationOptions.None).ToList();
            return files.Select(x => x.Name).ToList();
        }

        public List<string> FileNames
        (string directory, string filePrefix, string fileSuffixOrExtension = "")
        {
            /*https://winscp.net/eng/docs/file_mask*/
            string mask = filePrefix + "*" + fileSuffixOrExtension;
            var files = _session.EnumerateRemoteFiles
                        (directory, mask, EnumerationOptions.None).ToList();
            return files.Select(x => x.Name).ToList();
        }

        public bool IsConnected()
        {
            var value = _session == null ? false : _session.Opened;
            return value;
        }

        public void Disconnect()
        {
            _session.Close();
        }

        public void UploadFile(string localFilePath, string remoteFilePath)
        {
            TransferOptions transferOptions = new TransferOptions();
            transferOptions.TransferMode = TransferMode.Binary;
            TransferOperationResult transferResult = 
            _session.PutFiles(localFilePath, remoteFilePath, false, transferOptions);
            transferResult.Check();
        }

        public void DownloadFile(string localFilePath, string remoteFilePath)
        {
            TransferOptions transferOptions = new TransferOptions();
            transferOptions.TransferMode = TransferMode.Binary;
            TransferOperationResult transferResult = 
            _session.GetFiles(remoteFilePath, localFilePath, false, transferOptions);
            transferResult.Check();
        }

        public bool FileExists(string filePath)
        {
            bool has = _session.FileExists(filePath);
            return has;
        }

        public bool DirectoryExists(string directoryPath)
        {
            bool has = _session.FileExists(directoryPath);
            return has;
        }

        public void CreateDirectoryIfNotExists(string directoryPath)
        {
            if (!DirectoryExists(directoryPath))
            {
                _session.CreateDirectory(directoryPath);
            }
        }

        public void DeleteFileIfExists(string filePath)
        {
            if (DirectoryExists(filePath))
            {
                _session.RemoveFile(filePath);
            }
        }

        public void Dispose()
        {
            if (_session != null)
            {
                _session.Dispose();
            }
        }
    }
}

Using the Code

Here are the uses of the SFTP/FTP adapter classes:

RemoteSystemSetting setting = new RemoteSystemSetting()
{
    Type = "Ftp",           /*for sftp use "Sftp" and for ftp use "Ftp"*/
    Host = "xx.xx.xx.xx",   /*host ip*/
    Port = 21,              /*ftp:21, sftp:22*/
    UserName = "xyz",
    Password = "abc"
};

IRemoteFileSystemContext remote = new FtpSftpFileContext(setting);

remote.Connect();                                       /*establish connection*/
remote.DownloadFile("C:\\1.txt", "/test/1.txt");        /*download file*/
remote.UploadFile("C:\\2.txt", "/test/2.txt");          /*upload upload file*/
List<string> files = remote.FileNames("/test/");        /*file names*/
files = remote.FileNames("/test/",  "1", ".txt");       /*search file with prefix, suffix*/

/*others*/
bool value;
value = remote.IsConnected();                           /*check connection done or not*/
value = remote.DirectoryExists("/test/");               /*check if directory exists or not*/
remote.CreateDirectoryIfNotExists("/test/lol/");        /*create directory*/
value = remote.FileExists("/files/test/1.txt");         /*check if file exists or not*/
remote.DeleteFileIfExists("/test/2.txt");               /*delete file*/
remote.Disconnect();                                    /*stop connection*/
remote.Dispose();                                       /*dispose*/

Future Works

Going to add them soon.

/*we don't have, but going to add some*/
/*get all directory name*/
/*download all files*/
/*upload all files*/

About the Source Code

It a Visual Studio 2017 solution and .NET Framework 4.5 projects.

  • DotNetFtpSftp: console app

The code may throw unexpected errors for untested inputs. If any, just let me know.

How to Do the Same for ASP.NET CORE?

History

  • 20th July, 2020: Initial version