edtFTPnet/PRO Examples

How to connect to an FTP server

public void Run(string serverAddress, int serverPort, string userName, string password)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();
    
    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress;
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;

    // connect to the server
    // By default, auto-login is on so Login doesn't need to be called
    PrintLine("Connecting to server " + serverAddress);
    ftpConnection.Connect();

    // get the current working directory and files
    PrintLine("Working directory is " + ftpConnection.ServerDirectory);

    // Shut down client
    PrintLine("Closing client");
    ftpConnection.Close();

    PrintLine("Example complete");
}

How to connect to an FTP server

Connecting to an FTP server with edtFTPnet/PRO is simply a matter of:

  1. Creating an FTPConnection object

    FTPConnection ftpConnection = new FTPConnection();
    
  2. Setting the address and login properties

    ftpConnection.ServerAddress = "";
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;
    
  3. Calling the Connect() method.

    ftpConnection.Connect();
    

The Connect call will return when it's successfully connected and logged into the server, or throw an exception if it fails to connect or log in.

Note that ExFTPConnection and SecureFTPConnection also offer an asynchronous version of the Connect method, called BeginConnect, which returns instantly and performs the connection/login operation in the background. Please refer to the How to use asynchronous methods topic to learn more about this.

How to get a directory listing

public void Run(string serverAddress, int serverPort, string userName, string password)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();
            
    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress;
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;
    
    // connect to server
    PrintLine("Connecting to server " + serverAddress);
    ftpConnection.Connect();

    // get the current working directory and files
    PrintLine("Working directory is " + ftpConnection.ServerDirectory);

    // get a simple string listing
    PrintLine("Simple listing");
    string[] files = ftpConnection.GetFiles();
    foreach (string file in files)
    {
            PrintLine("  " + file);
    }

    // get file details
    PrintLine("Detailed listing");
    FTPFile[] fileDetails = ftpConnection.GetFileInfos();
    foreach (FTPFile file in fileDetails)
    {
        if (file.Dir)
            PrintLine("  " + file.Name + " (directory)");
        else
            PrintLine("  " + file.Name + " (" + file.Size + " bytes)");
    }

    // Shut down client
    PrintLine("Closing client");
    ftpConnection.Close();

    PrintLine("Example complete");
}

How to get a directory listing

There are two basic ways to get a list of the files in a particular directory on an FTP server. The simpler way gets the names of the files using the GetFiles() method:

string[] files = ftpConnection.GetFiles();

This results in the files array containing the name of the files and directories in the current working directory on the server.

Often more information that just the name of the file/directory is required. In such cases, the GetFileInfos() method should be used:

FTPFile[] fileDetails = ftpConnection.GetFileInfos();

This method returns an array of FTPFile objects containing information about the files in the directory - details such as the size of the file and whether or not it is a directory.

If a listing of a directory other than the current working directory is required then the relative or absolute path may be passed to either method. For example:

string[] files = ftpConnection.GetFiles(directoryPath);

Alternatively, the working directory may be changed as explained in How to change directories.

Note that ExFTPConnection and SecureFTPConnection also offer asynchronous versions of these methods. These are recommended for improving the responsiveness of GUI applications. Please refer to the How to use asynchronous methods topic to learn more about this.

How to change directories

public void Run(string serverAddress, int serverPort, string userName, string password,
                string subdirectory)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();
    
    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress;
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;
    
    // connect to server
    PrintLine("Connecting to server " + serverAddress);
    ftpConnection.Connect();

    // get the current working directory
    PrintLine("Initial directory is " + ftpConnection.ServerDirectory);

    // change directory
    ftpConnection.ChangeWorkingDirectory(subdirectory);
    PrintLine("Changed to subdirectory " + ftpConnection.ServerDirectory);

    // go back to the parent directory
    ftpConnection.ChangeWorkingDirectoryUp();
    PrintLine("Changed back to original directory " + ftpConnection.ServerDirectory);

    // Shut down client
    PrintLine("Closing client");
    ftpConnection.Close();

    PrintLine("Example complete");
}

How to change directories

While you are connected to an FTP server, the server keeps track of your working directory. The server assumes you are referring to this directory whenever you perform a file operation without specifying an absolute path.

The current working directory is available in the WorkingDirectory property:

string directory = ftpConnection.WorkingDirectory;

This may be changed using:

ftpConnection.<a href="../api/html/M_EnterpriseDT_Net_Ftp_FTPConnection_ChangeWorkingDirectory.htm">ChangeWorkingDirectory(directory);</a>

Or to simply go up to the parent directory:

ftpConnection.<a href="../api/html/M_EnterpriseDT_Net_Ftp_FTPConnection_ChangeWorkingDirectoryUp.htm">ChangeWorkingDirectoryUp()</a>

Note that ExFTPConnection and SecureFTPConnection also offer asynchronous versions of these methods. These are recommended for improving the responsiveness of GUI applications. Please refer to the How to use asynchronous methods topic to learn more about this.

How to upload, download and delete a file

public void Run(string serverAddress, int serverPort, string userName, 
                string password, string fileName)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();
    
    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress;
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;
    
    // connect to server
    PrintLine("Connecting to server " + serverAddress);
    ftpConnection.Connect();

    // get the current working directory and files
    PrintLine("Working directory is " + ftpConnection.ServerDirectory);

    // upload it to the server
    ftpConnection.UploadFile(fileName, fileName);
    PrintLine("Uploaded file '" + fileName + "'");

    // download it with a new name
    string newFile = fileName + ".copy";
    ftpConnection.DownloadFile(newFile, fileName);
    PrintLine("Downloaded file '" + newFile + "'");

    // delete the file on the server
    ftpConnection.DeleteFile(fileName);
    PrintLine("Deleted file from server '" + fileName + "'");

    // Shut down client
    PrintLine("Closing client");
    ftpConnection.Close();

    PrintLine("Example complete");
}

How to upload, download and delete a file

Uploading, downloading, and deletion of files is all done through simple method calls on the FTPConnection class.

Uploading files

Uploading of a file is done by the following method-call:

ftpConnection.<a href="../api/html/Overload_EnterpriseDT_Net_Ftp_FTPConnection_UploadFile.htm">UploadFile(localFilePath, remoteFileName);</a>

This method uploads the file specified by the first argument and saves it on the server with the name specified by the second argument. If the file is already present on the server then it is usually overwritten, though this depends on the server configuration.

SecureFTPConnection also supports file appending whereby any data that is in the local file but not in the remote file is appended to the end of the remote file. For example, if the local file is 100k in length, but the remote file is only 80k, then the last 20k of the local file is appended to the remote file. This feature can be useful for continuing interrupted downloads or updating log files. It is done by passing true as a third parameter to the UploadFile method:

ftpConnection.UploadFile(localFilePath, remoteFileName, true)

Downloading files

Downloading of a file is done by the following method-call:

ftpConnection.DownloadFile(localFilePath, remoteFileName)

This method downloads the file specified by the second argument and saves it locally with the name specified by the first argument. If the file is already present on the local storage medium then it is overwritten.

Deleting files

A file may be deleted by calling the DeleteFile method.

Notes

  1. It is often useful to transfer data directly to and from memory rather than files. The topic How to transfer streams and byte-arrays explains how to do this.
  2. ExFTPConnection and SecureFTPConnection also offer asynchronous versions of these methods. These are recommended for improving the responsiveness of GUI applications. Please refer to the How to use asynchronous methods topic to learn more about this.

How to transfer directly from/to memory

public void Run(string serverAddress, int serverPort, string userName, string password, string fileName)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();

    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress; 
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;
    
    // connect to server
    PrintLine("Connecting to server " + serverAddress);
    ftpConnection.Connect();

    // get data to be transferred
    string s = "Hello world";
    byte[] bytes = Encoding.ASCII.GetBytes(s);

    // upload the byte-array to a file on the server
    PrintLine("Uploading byte-array to the file '" + fileName + "'");
    ftpConnection.UploadByteArray(bytes, fileName);

    // download byte-array and display it
    PrintLine("Downloading the file '" + fileName + "' into a byte-array");
    bytes = ftpConnection.DownloadByteArray(fileName);
    PrintLine("Downloaded string = " + Encoding.ASCII.GetString(bytes));

    // build StringStream (defined below) for "Hello world"
    StringStream inStr = new StringStream(s);

    // upload the stream to a file on the server
    PrintLine("Uploading stream to the file '" + fileName + "'");
    ftpConnection.UploadStream(inStr, fileName);
    inStr.Close();

    // create a StringStream to download into
    StringStream outStr = new StringStream();
    PrintLine("Downloading the file '" + fileName + "' into a stream");
    ftpConnection.DownloadStream(outStr, fileName);
    PrintLine("Downloaded string = " + outStr.ToString());
    outStr.Close();
    
    // Shut down client
    PrintLine("Closing client");
    ftpConnection.Close();

    PrintLine("Example complete");
}

class StringStream : Stream
{
    private MemoryStream buffer;
    
    public StringStream()
    {
        buffer = new MemoryStream();
    }

    public StringStream(string str)
    {
        buffer = new MemoryStream(Encoding.ASCII.GetBytes(str));
    }

    public override int Read(byte[] bytes, int offset, int count)
    {
        return buffer.Read(bytes, offset, count);
    }

    public override void Write(byte[] bytes, int offset, int count)
    {
        buffer.Write(bytes, offset, count);
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        return buffer.Seek(offset, origin);
    }

    public override string ToString()
    {
        return Encoding.ASCII.GetString(buffer.GetBuffer());
    }

    public override bool CanRead
    {
        get
        {
            return true;
        }
    }

    public override bool CanWrite
    {
        get
        {
            return true;
        }
    }

    public override bool CanSeek
    {
        get
        {
            return true;
        }
    }

    public override void Flush()
    {
        buffer.Flush();
    }

    public override long Length
    {
        get
        {
            return buffer.Length;
        }
    }

    public override void SetLength(long value)
    {
        buffer.SetLength(value);
    }

    public override long Position
    {
        get
        {
            return buffer.Position;
        }
        set
        {
            buffer.Position = value;
        }
    }
}

How to transfer directly from/to memory

One of the advantages of integrating FTP functionality directly into a product rather than using stand-alone FTP applications is that data can be transferred directly to and from memory. This is particularly useful when transferring dynamic content needs, such as the results database queries and other application data.

FTPConnection offers two alternatives for memory transfers: byte-arrays and streams. Byte- arrays are generally easier to deal with but do not facilitate streaming. In other words, the data must be fully generated and stored in a byte-array before being transferred. This is fine when memory usage is not an issue, but if it is necessary to limit memory usage then streams should be used.

Byte-Array Transfers are performed using the DownloadByteArray and UploadByteArray methods. They simply take the byte-array and the remote file-name as a parameter.

string s = "Hello world";
 byte[] bytes = Encoding.ASCII.GetBytes(s);
 ftpConnection.UploadByteArray(bytes, remoteFileName); 

Stream Transfers allow the programmer to delay creation of the data to be transferred until it is ready to be transferred. For example, the data to be transferred might be the result of a database query that could return millions of rows. In such a case, storing it all in memory at once would be inefficient. To circumvent this problem a custom stream may be written which uses a cursor to iterate through the query result as the file is being transferred.

To transfer streams, the methods DownloadStream and UploadStream should be used. If a suitable Stream is not available from the standard libraries a new one may be created by extending the System.IO.Stream class and overriding the appropriate read and/or write methods.

The following code-snippet shows code and pseudo-code that illustrates the use of a custom stream to upload the results of a query to an FTP server:

SqlDataStream dbStr = new SqlDataStream(sqlDataReader);
 ftpConnection.UploadStream(dbStr, remoteFileName);
 .
 .
 .
 public class SqlDataStream : Stream
 {
 private MemoryStream buffer = new MemoryStream();
 public override int Read(byte[] bytes, int offset, int count)
 {
 if (not enough bytes in buffer)
 ReadFromDatabase(count)
 int numBytes = buffer.Read(bytes, 0, count);
 remove read bytes from buffer
 } 
 private void ReadFromDatabase(int count)
 {
 1. write remainder of fields from current record to the buffer
 2. read sufficient records from the database such that there are at least 'count' bytes in the buffer
 }

Note that ExFTPConnection and SecureFTPConnection also offer asynchronous versions of these methods. These are recommended for improving the responsiveness of GUI applications. Please refer to the How to use asynchronous methods topic to learn more about this.

How to transfer multiple files with wildcards

public void Run(string serverAddress, int serverPort, string userName, string password, 
                string directory, string wildcard)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();

    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress;
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;

    // connect to the server
    // By default, auto-login is on so Login doesn't need to be called
    PrintLine("Connecting to server " + serverAddress);
    ftpConnection.Connect();

    // add an event-handler so we can see what files were downloaded
    ftpConnection.Downloaded += new FTPFileTransferEventHandler(ftpConnection_Downloaded);

    // download the files using the wildcard
    ftpConnection.DownloadMultiple(directory, wildcard);

    // Shut down client
    PrintLine("Closing client");
    ftpConnection.Close();

    PrintLine("Example complete");
}

// event-handler printing the name and size of a downloaded file
private void ftpConnection_Downloaded(object sender, FTPFileTransferEventArgs e)
{
    PrintLine("Downloaded file " + e.RemoteFile + " of size " + e.FileSize);
}

How to transfer multiple files with wildcards

edtFTPnet/PRO is able to download and upload multiple files and directories in a single method call.

These capabilities are not available in FTPConnection, but are in ExFTPConnection and SecureFTPConnection.

The relevant methods are listed below:

void DownloadMultiple<(string localDir, string remoteDir, string wildcard, bool includeSubDirs)
void DownloadMultiple(string localDir, string remoteDir, FileFilter filter, bool includeSubDirs)
void UploadMultiple(string localDir, string remoteDir, string wildcard, bool includeSubDirs)
void UploadMultiple(string localDir, string remoteDir, FileFilter filter, bool includeSubDirs)

The arguments to each of these methods are (1) the path of the directory in the local file- system, (2) the path of the directory on the server, (3) a wildcard or a FileFilter, and (4) a flag indicating whether or not to include subdirectories.

The wildcard argument is a string that may contain markers for unknown characters. The question mark (?) character matches a single unknown character. The asterisk (*) character matches one or more unknown characters. For example, the wildcard "file*.dat" would match the following strings, "file1.dat", "file10.dat", "fileA.dat", and "fileABC.dat", whereas the wildcard "file?.dat" would match the following strings, "file1.dat" and "fileA.dat", but not "file10.dat" and "fileABC.dat".

FileFilter is somewhat more complex, but also a lot more powerful. It is a delegate, so it may be used to reference a method. It takes an FTPFile object as an argument and returns a bool. The FTPFile object describes a local file when uploading and a remote file when downloading. This method must have the following signature:

bool MethodName(FTPFile file)

where MethodName can be any valid method-name.

As an example, if one wanted to download any files less than 1000 bytes, then one would define the following method:

bool IsFileSmall(FTPFile file)
 {
 return file.Size<=1000;
 }

and would then use it as follows:

ftpConnection.DownloadMultiple(localDir, remoteDir, new FileFilter(IsFileSmall), false);

In this case, the final argument is false meaning that only files from the directory specified by remoteDir will be downloaded and files in subdirectories will be bypassed.

How to transfer multiple files with filters

public void Run(string serverAddress, int serverPort, string userName, string password, 
                string directory, int maxSize)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();

    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress;
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;

    // remember the maximum size we're allowing
    this.maxSize = maxSize;

    // connect to the server
    // By default, auto-login is on so Login doesn't need to be called
    PrintLine("Connecting to server " + serverAddress);
    ftpConnection.Connect();

    // add an event-handler so we can see what files were downloaded
    ftpConnection.Downloaded += new FTPFileTransferEventHandler(ftpConnection_Downloaded);

    // download the files using the filter
    ftpConnection.DownloadMultiple(directory, new FileFilter(IsFileSmall));

    // Shut down client
    PrintLine("Closing client");
    ftpConnection.Close();

    PrintLine("Example complete");
}

// stores the maximum size as used in the IsFileSmall method
private long maxSize;

// filtering method which returns true if the file is less than maxSize
public bool IsFileSmall(FTPFile file)
{
    return file.Size<=maxSize;
}

// event-handler printing the name and size of a downloaded file
private void ftpConnection_Downloaded(object sender, FTPFileTransferEventArgs e)
{
    PrintLine("Downloaded file " + e.RemoteFile + " (" + e.FileSize + " bytes)");
}

How to transfer multiple files with filters

edtFTPnet/PRO is able to download and upload multiple files and directories in a single method call.

These capabilities are not available in FTPConnection, but are in ExFTPConnection and SecureFTPConnection.

The relevant methods are listed below:

void <a href="../api/html/Overload_EnterpriseDT_Net_Ftp_ExFTPConnection_DownloadMultiple.htm">DownloadMultiple</a>(string localDir, string remoteDir, string wildcard, bool includeSubDirs)
 void <a href="../api/html/Overload_EnterpriseDT_Net_Ftp_ExFTPConnection_DownloadMultiple.htm">DownloadMultiple</a>(string localDir, string remoteDir, FileFilter filter, bool includeSubDirs)
 void <a href="../api/html/Overload_EnterpriseDT_Net_Ftp_ExFTPConnection_UploadMultiple.htm">UploadMultiple</a>(string localDir, string remoteDir, string wildcard, bool includeSubDirs)
 void <a href="../api/html/Overload_EnterpriseDT_Net_Ftp_ExFTPConnection_UploadMultiple.htm">UploadMultiple</a>(string localDir, string remoteDir, FileFilter filter, bool includeSubDirs)

The arguments to each of these methods are (1) the path of the directory in the local file- system, (2) the path of the directory on the server, (3) a wildcard or a FileFilter, and (4) a flag indicating whether or not to include subdirectories.

The wildcard argument is a string that may contain markers for unknown characters. The question-mark (?) character matches a single unknown character. The asterisk (*) character matches one or more unknown character. For example, the wildcard "file*.dat" would match the following strings, "file1.dat", "file10.dat", "fileA.dat", and "fileABC.dat", whereas the wildcard "file?.dat" would match the following strings, "file1.dat" and "fileA.dat", but not "file10.dat" and "fileABC.dat".

FileFilter is somewhat more complex, but also a lot more powerful. It is a delegate, so it may be used to reference a method. It takes an FTPFile object as an argument and returns a bool. The FTPFile object describes a local file when uploading and a remote file when downloading. This method must have the following signature:

bool MethodName(FTPFile file)

where MethodName can be any valid method-name.

As an example, if one wanted to download any files less than 1000 bytes, then one would define the following method:

bool IsFileSmall(FTPFile file)
 {
 return file.Size<=1000;
 }

and would then use it as follows:

ftpConnection.DownloadMultiple(localDir, remoteDir, new FileFilter(IsFileSmall), false);

In this case, the final argument is false meaning that the only file from the directory specified by remoteDir will be downloaded and files in subdirectories will be bypassed.

How to use FTP events

public void Run(string serverAddress, int serverPort, string userName, string password)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();
    
    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress;
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;

    // hook up event-handlers
    ftpConnection.Connected += new EnterpriseDT.Net.Ftp.FTPConnectionEventHandler(ftpConnection_Connected);
    ftpConnection.Closed += new EnterpriseDT.Net.Ftp.FTPConnectionEventHandler(ftpConnection_Closed);
    
    // connect to server
    PrintLine("Connecting to server " + serverAddress);
    ftpConnection.Connect();

    // get the current working directory and files
    PrintLine("Working directory is " + ftpConnection.ServerDirectory);
    
    // Shut down client
    PrintLine("Closing client");
    ftpConnection.Close();

    PrintLine("Example complete");
}

private void ftpConnection_Connected(object sender, EnterpriseDT.Net.Ftp.FTPConnectionEventArgs e)
{
    PrintLine("Connected to " + e.ServerAddress + ":" + e.ServerPort);
}

private void ftpConnection_Closed(object sender, EnterpriseDT.Net.Ftp.FTPConnectionEventArgs e)
{
    PrintLine("Disconnected from " + e.ServerAddress + ":" + e.ServerPort);
}

How to use FTP events

edtFTPnet/PRO's events are useful for providing feedback on the progress of FTP operations. For example, the BytesTransferred event fires during a file transfer each time another n bytes have been transferred, where n is equal to FTPConnection.TransferNotifyInterval. An event such as this may be used to provide progress feedback during long transfer operations.

Handling events is done using delegates in the same way as other .NET events. For example, to handle the Connected event, an event handler must be defined:

privatevoid ftpConnection_Connected(object sender, EnterpriseDT.Net.Ftp.FTPConnectionEventArgs e)
{
 Print("Connected to "; + e.ServerAddress + ":" + e.ServerPort);
}

A delegate for this event-handler must then be added to the event:

ftpConnection.Connected += new FTPConnectionEventHandler(ftpConnection_Connected);

Once this has been done, the ftpConnection_Connect method will be called when a connection with the server has been established.

The following events relate to specific FTP operations. Most events are available in FTPConnection, however certain security-related events are only available in SecureFTPConnection:

ClosedOccurs when the component has closed its connection to the server.
ClosingOccurs when the component is about to close its connection to the
server.
ConnectedOccurs when the component has connected to the server.
ConnectingOccurs when the component is connecting to the server.
DeletedOccurs when a file has been deleted from the server.
DeletingOccurs when a file is about to be deleted from the server.
DirectoryChangedOccurs when the working directory on the server has been changed.
DirectoryChangingOccurs when the working directory on the server is about to be changed.
DownloadedOccurs when a file has been downloaded from the server.
DownloadingOccurs when a file is about to be downloaded from the server.
LoggedInOccurs when the component has logged in.
LoggingInOccurs when the component is about to log in.
RenamedFileOccurs when a remote file has been renamed.
RenamingFileOccurs when a remote file is about to be renamed.
SecuredConnectionOccurs when the component has secured the connection to the server.
SecuringConnectionOccurs when the component is securing the connection to the server.
ServerValidateServer validation event.
UploadedOccurs when a file has been uploaded to the server.
UploadingOccurs when a file is about to be uploaded to the server.

The following events are of a more general nature and can occur across a range of FTP operations:

BytesTransferredOccurs every time a specified number of bytes of data have been
transferred.
CommandSentOccurs when a command is sent to the server.
ErrorOccurs when an exception is thrown during an asynchronous operation.
ReplyReceivedOccurs when a reply is received from the server.

The Error event is of particular importance when using asynchronous processing since it is called if an exception is thrown occurs during an FTP operation. The topic How to use asynchronous methods has information about using events with asynchronous methods.

How to use asynchronous methods

public void Run(string serverAddress, int serverPort, string userName, 
                string password, string fileName)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();
    
    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress;
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;
    
    // connect to the server
    PrintLine("Queuing connection to " + serverAddress);
    ftpConnection.BeginConnect(new AsyncCallback(OnConnect), ftpConnection);

    // upload it to the server
    PrintLine("Queuing UploadFile");
    ftpConnection.BeginUploadFile(fileName, fileName, new AsyncCallback(OnUpload), ftpConnection);

    // get the size of the file we've just uploaded
    PrintLine("Queuing GetSize");
    ftpConnection.BeginGetSize(fileName, new AsyncCallback(OnGetSize), ftpConnection);

    // download it with a new name
    string newFile = fileName + ".copy";
    PrintLine("Queuing DownloadFile");
    ftpConnection.BeginDownloadFile(newFile, fileName, new AsyncCallback(OnDownload), ftpConnection);

    // delete the file on the server
    PrintLine("Queuing DeleteFile");
    ftpConnection.BeginDeleteFile(fileName, new AsyncCallback(OnDelete), ftpConnection);

    // Shut down client
    PrintLine("Queuing Close");
    ftpConnection.BeginClose(new AsyncCallback(OnClose), ftpConnection);

    // Wait for completion of Close operation
    PrintLine("All operations queued.  Waiting for signal");
    Print();
    signaller.WaitOne();

    PrintLine("Example complete");
}

private void OnConnect(IAsyncResult ar)
{
    SecureFTPConnection c = (SecureFTPConnection)ar.AsyncState;
    c.EndConnect(ar);
    PrintLine("Connect completed");
}

private void OnUpload(IAsyncResult ar)
{
    SecureFTPConnection c = (SecureFTPConnection)ar.AsyncState;
    c.EndUploadFile(ar);
    PrintLine("Upload completed");
}

private void OnGetSize(IAsyncResult ar)
{
    SecureFTPConnection c = (SecureFTPConnection)ar.AsyncState;
    long size = c.EndGetSize(ar);
    PrintLine("GetSize completed: size = " + size + " bytes");
}

private void OnDownload(IAsyncResult ar)
{
    SecureFTPConnection c = (SecureFTPConnection)ar.AsyncState;
    c.EndDownloadFile(ar);
    PrintLine("Download completed");
}

private void OnDelete(IAsyncResult ar)
{
    SecureFTPConnection c = (SecureFTPConnection)ar.AsyncState;
    c.EndDeleteFile(ar);
    PrintLine("Delete completed");
}

private void OnClose(IAsyncResult ar)
{
    SecureFTPConnection c = (SecureFTPConnection)ar.AsyncState;
    c.EndClose(ar);
    PrintLine("Close completed.  Signalling main thread");
    Print();
    signaller.Set();
}

private ManualResetEvent signaller = new ManualResetEvent(false);

How to use asynchronous methods

The regular, synchronous forms of the FTP operations presented through the FTPConnection interface do not return until the operation that they're performing has been completed. If the connection to the server is slow or if a large file is being transferred then this can result in unacceptable performance, particularly for GUI applications and other applications where FTP operations are performed interactively with a user. This is why ExFTPConnection (and SecureFTPConnection) provide advanced asynchronous (or background) functionality.

Most regular methods present in the FTPConnection interface have asynchronous counterparts. For each synchronous method, there is a corresponding pair of method of the same name, but with Begin and End prefixes.

For example, the Connect() method corresponds to BeginConnect() and EndConnect(). In the following code, the Print statement is not executed until after the connection to the server has been established.

ftpConnection.Connect();
Print("Connected");

It is common for it to take several seconds to establish a connection so, even this simple task can result in unacceptable GUI performance.

When this is recoded using asynchronous methods, as follows:

ftpConnection.BeginConnect(new AsyncCallback(OnConnect), null;
Print("Connecting");

the BeginConnect() method does not wait for the connection to be established before returning and allowing processing to continue. Instead, executing immediately returns to the next instruction and the connection is established concurrently on a worker-thread. It is of course necessary to know when the connection has been established; this is what the AsyncCallback delegate is for. In this case, this delegate instructs ExFTPConnection to call the method OnConnect() once the connection has been established. This method is defined as follows:

private void OnConnect(IAsyncResult ar)
{
 Print("Connected");
}

Since the Connect() operation does not return a value, there is no need to call the EndConnect() method. Some FTP operations do however return values. In such cases the EndX() method returns the value as illustrated in the following example:

ftpConnection.BeginGetSize(fileName, new AsyncCallback(OnGetSize), ftpConnection);
 .
 .
 .
 private void OnGetSize(IAsyncResult ar)
 {
 SecureFTPConnection c = (SecureFTPConnection)ar.AsyncState;
 long size = c.EndGetSize(ar);
 Print("size = " + size + " bytes");
 }

The asynchronous approach allows the developer to write a highly responsive interface that responds instantly to user actions and provides feedback on how processing is progressing.

Queuing FTP operations

Unlike other similar implementations, ExFTPConnection allows multiple operations to be queued. In other words, multiple Begin operations may be invoked without delay. They will be processed in the order in which they're added. They will all be executed on the same thread and the callback methods will be invoked between each operation.

Preventing callbacks and event-handlers from hanging

ExFTPConnection has been designed to make asynchronous processing and event-handling as easy as possible, but occasionally it is necessary to understand how the processing is performed in order to avoid problems that can be difficult to diagnose.

In a Windows Forms application, all calls that update the user-interface should be executed on one particular thread. When this rule is not adhered to, .NET 1.1 will exhibit hanging behavior and .NET 2.0 will throw InvalidOperationExceptions. Microsoft calls such cases "cross-thread calls".

When asynchronous methods are used, ExFTPConnection employs a worker-thread to process FTP operations. This frees the GUI thread to continue updating the screen and processing user inputs. However, the decision of which thread the callback should be executed on is not clear-cut. By default, ExFTPConnection will run asynchronous callbacks and event-handlers on the GUI thread if one is available. This is generally the most useful since such event-handlers are often used to provide some sort of user-interface-related action. This behavior can, however, be changed through the UseGuiThreadIfAvailable property. If this property is set to false then asynchronous callbacks and event-handlers will be executed on the worker-thread. This is sometimes desirable for performance reasons since it doesn't tie up the GUI thread unnecessarily.

How to FTP through a SOCKS proxy

public void Run(string serverAddress, int serverPort, string userName, string password, 
                string proxyAddress, int proxyPort, string proxyUserName, string proxyPassword)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();
            
    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress;
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;

    // set up SOCKS server
    Socks5Context socks = new Socks5Context(proxyAddress, proxyPort);
    socks.AuthMethods.Add(new Socks5UserNamePasswordAuthMethod(proxyUserName, proxyPassword));
    ftpConnection.SocksProxySettings = socks;
    
    // connect to server
    PrintLine("Connecting to server " + serverAddress);
    ftpConnection.Connect();

    // get the current working directory and files
    PrintLine("Files in directory " + ftpConnection.ServerDirectory + ":");
    PrintLines(ftpConnection.GetFiles());
    
    // Shut down client
    PrintLine("Closing client");
    ftpConnection.Close();

    PrintLine("Example complete");
}

How to FTP through a SOCKS proxy

SOCKS is a protocol that many proxy servers use to communicate with clients. It allows computers behind a firewall to communicate with computers outside the firewall. During this communication the proxy server acts as a relay for information sent in both directions. Please refer to the topic Proxies for more information on this.

All SOCKS options are set using the ProxySettings group of properties.

Firstly, the protocol must be chosen via the ProxyType. The default is NoProxy. One of Socks4, Socks4A and Socks5 option should be selected (there is also Http, for HTTP proxies).

All proxies require the ProxyAddress to be set, and optionally the ProxyPort.

SOCKS4 and SOCKS4A simply require the UserName to be set. No password is required. Note that with SOCKS4A domain names are passed to the server for resolution to IP addresses.

SOCKS5 requires at least one SOCKS5 authentication method to be enabled. One or more of the NullAuthenticationEnabled and PasswordAuthenticationEnabled flags should be set to true. If password authentication is enabled, the Password property must also be set.

Note that SOCKS were previously set via the SocksProxySettings property, and the SOCKS editor. This is now obsolete, and all proxy settings should be set via the ProxySettings group of properties. SocksProxySettings in existing code will continue to work, however, all new code should use ProxySettings.

How to use FTPS (without server validation)

public void Run(string serverAddress, int serverPort, string userName, string password)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();
    
    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress;
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;
    
    // select explicit FTPS
    ftpConnection.Protocol = FileTransferProtocol.FTPSExplicit;
    
    // switch off server validation (unsafe - only do this when testing)
    ftpConnection.ServerValidation = SecureFTPServerValidationType.None;
    
    // connect to server
    PrintLine("Connecting to server " + serverAddress);
    ftpConnection.Connect();
    
    // get the current working directory and files
    PrintLine("Files in directory " + ftpConnection.ServerDirectory + ":");
    PrintLines(ftpConnection.GetFiles());
    
    // Shut down client
    PrintLine("Closing client");
    ftpConnection.Close();
    
    PrintLine("Example complete");
}

How to use FTPS (without server validation)

The topic How to use FTPS (introduction) describes the FTPS features of SecureFTPConnection. This topic demonstrates the use of FTPS without server validation. Server validation should always be used in a production environment, but disabling it is a good way of getting started.

IMPORTANT: An FTPS compatible FTP server is required for this example. You can download a free trial of CompleteFTP, a Windows FTPS server, from this link.

Using FTPS without server validation is simply a matter of setting the Protocol and ServerValidation properties as follows:

fftpConnection.Protocol = FileTransferProtocol.FTPSExplicit;
ftpConnection.ServerValidation = SecureFTPServerValidationType.None;

The first line tells SecureFTPConnection that it is to use explicit FTPS and the second line that it should not try to validate the server's certificate.

After this a secure connection is established by simply calling Connect():

ftpConnection.Connect();

How to use FTPS (with server validation - Part A)

public void Run(string serverAddress, int serverPort, string userName, string password)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();
    
    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress;
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;
    
    // select explicit FTPS
    ftpConnection.Protocol = FileTransferProtocol.FTPSExplicit;
    
    // show certificate manager to allow user to install the server's
    // certificate or the certificate of the CA that issued it.
    PrintLine("Displaying certificate manager");
    SSLFTPCertificate.ShowCertificateManager("Please ensure that the server's certificate is installed", null);
    
    // select automatic validation of the server's certificate.  The certificate, 
    // or that of the CA that issued it, must be installed into the operating 
    // system's certificate store before this example will work.
    ftpConnection.ServerValidation = SecureFTPServerValidationType.Automatic;
    
    // connect to server
    PrintLine("Connecting to server " + serverAddress);
    ftpConnection.Connect();
    
    // get the current working directory and files
    PrintLine("Files in directory " + ftpConnection.ServerDirectory + ":");
    PrintLines(ftpConnection.GetFiles());
    
    // Shut down client
    PrintLine("Closing client");
    ftpConnection.Close();
    
    PrintLine("Example complete");
}

How to use FTPS (with server validation - Part A)

The topic, How to use FTPS (introduction), describes the FTPS features of SecureFTPConnection. This topic demonstrates the use of FTPS with server validation in the case where the server certificate's CommonName (CN) is the same as its address.

IMPORTANT: An FTPS compatible FTP server is required for this example. You can download a free trial of CompleteFTP, a Windows FTPS server, from this link.

As in FTPS without server validation, the Protocol and ServerValidation properties must be set:

ftpConnection.Protocol = FileTransferProtocol.FTPSExplicit;
ftpConnection.ServerValidation = SecureFTPServerValidationType.Automatic;

Setting ServerValidation to Automatic instructs SecureFTPConnection to match the certificate that the server presents against those in the Windows Certificate Store or a pre-loaded certificate. This means that either of the following must be true:

  1. the server certificate has been issued by a Certificate Authority, such as VeriSign or Thawte, whose certificate is in the Windows Certificate store (the “Trusted Root Certification Authorities”); OR
  2. the server's certificate itself is in the Windows Certificate store (the “Trusted Root Certification Authorities”); OR
  3. the server's certificate is loaded into directly into SecureFTPConnection's ServerValidationCertificate property.

In the first case no manipulation of the Windows Certificate store is necessary. Most population Certificate Authority certificates are installed in the store by default.

In the second case it is necessary to install the server certificate on the machine on which SecureFTPConnection is being used. In order to make this simpler, edtFTPnet/PRO provides both design-time and runtime tools for managing certificates.

The Certificate Manager may be presented at runtime using the SSLFTPCertificate.ShowCertificateManager method:

SSLFTPCertificate.ShowCertificateManager();

This only needs to be done once since the certificate will remain in the store until it is removed.

In the third case the server certificate can be loaded into the ServerValidationCertificate property via the SSLFTPCertificate.CreateFromFile method.

Once the server certificate is loaded, or the Certificate Authority that issued it is in the Windows certificate store, the Connect() may simply be called to establish a secure connection:

ftpConnection.Connect();

While the secure connection is being established the CommonName (CN) of the server certificate is checked. If this check fails, the connection will fail. Please refer to How to use FTPS (with server validation - part B) and How to use FTPS (with server validation - part C) for more details on this issue.

How to use FTPS (with server validation - Part B)

public void Run(string serverAddress, int serverPort, string userName, string password,
                string certificateCommonName)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();
    
    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress;
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;
    
    // select explicit FTPS
    ftpConnection.Protocol = FileTransferProtocol.FTPSExplicit;
    
    // select automatic validation of the server's certificate.  The certificate, 
    // or that of the CA that issued it, must be installed into the operating 
    // system's certificate store before this example will work.
    ftpConnection.ServerValidation = SecureFTPServerValidationType.Automatic;
    
    // set the name that we want to match against the server certificate's 
    // Common Name (CN) label
    ftpConnection.ServerCommonName = certificateCommonName;
    
    // show certificate manager to allow user to install the server's
    // certificate or the certificate of the CA that issued it.
    PrintLine("Displaying certificate manager");
    SSLFTPCertificate.ShowCertificateManager("Please ensure that the server's certificate is installed", null);
    
    // connect to server
    PrintLine("Connecting to server " + serverAddress);
    ftpConnection.Connect();
    
    // get the current working directory and files
    PrintLine("Files in directory " + ftpConnection.ServerDirectory + ":");
    PrintLines(ftpConnection.GetFiles());
    
    // Shut down client
    PrintLine("Closing client");
    ftpConnection.Close();
    PrintLine("Example complete");
}

How to use FTPS (with server validation - Part B)

This topic continues from How to use FTPS (with server validation - part A).

Every certificate has a CommonName (CN) attribute. It is common for this attribute to be set to the host-name of the server. If, for example, the name of the server is ftp.mycompany.com the CN would be ftp.mycompany.com also. When the CN is not the same as the host-name then the ServerCommonName property must be set as follows:

ftpConnection.ServerCommonName = "ftp.mycompany.com";

Apart from this, configuration of the SecureFTPConnection is the same as in Part A.

How to use FTPS (with server validation - Part C)

public void Run(string serverAddress, int serverPort, string userName, string password)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();
    
    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress;
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;
    
    // select explicit FTPS
    ftpConnection.Protocol = FileTransferProtocol.FTPSExplicit;
    
    // select automatic validation of the server's certificate, bypassing the
    // CommonName check.  
    ftpConnection.ServerValidation = SecureFTPServerValidationType.AutomaticNoNameCheck;
    
    // The certificate, or that of the CA that issued it, must be installed into 
    // the operating system's certificate store before this example will work,
    // so we show certificate manager to allow user to install the server's
    // certificate or the certificate of the CA that issued it.
    PrintLine("Displaying certificate manager");
    SSLFTPCertificate.ShowCertificateManager("Please ensure that the server's certificate is installed", null);
    
    // connect to server
    PrintLine("Connecting to server " + serverAddress);
    ftpConnection.Connect();
    
    // get the current working directory and files
    PrintLine("Files in directory " + ftpConnection.ServerDirectory + ":");
    PrintLines(ftpConnection.GetFiles());
    
    // Shut down client
    PrintLine("Closing client");
    ftpConnection.Close();
    
    PrintLine("Example complete");
}

How to use FTPS (with server validation - Part C)

This topic continues from How to use FTPS (with server validation - part A) and How to use FTPS (with server validation - part B).

Sometimes it may be desirable to ignore the CommonName (CN) of the server's certificate completely. To configure SecureFTPConnection to this the ServerValidation property to AutomaticNoNameCheck:

ftpConnection.ServerValidation = SecureFTPServerValidationType.AutomaticNoNameCheck

In this case the server's certificate is still validated against those in the Windows certificate store, but its CommonName (CN) is ignored.

How to use FTPS (with client/server validation)

public void Run(string serverAddress, int serverPort, string userName, string password,
                string certificateCommonName)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();
    
    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress;
    ftpConnection.ServerPort = serverPort; 
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;
    
    // select explicit FTPS
    ftpConnection.Protocol = FileTransferProtocol.FTPSExplicit;
    
    // select automatic validation of the server's certificate.  The certificate, 
    // or that of the CA that issued it, must be installed into the operating 
    // system's certificate store before this example will work.
    ftpConnection.ServerValidation = SecureFTPServerValidationType.Automatic;
    
    // set the name that we want to match against the server certificate's 
    // Common Name (CN) label
    ftpConnection.ServerCommonName = certificateCommonName;
    
    // prompt for a client certificate and private key
    ftpConnection.ClientCertificate = SSLFTPCertificate.PromptForCertificate(true);
    
    // The server's certificate, or that of the CA that issued it, must be installed into 
    // the operating system's certificate store before this example will work,
    // so we show certificate manager to allow user to install the server's
    // certificate or the certificate of the CA that issued it.
    PrintLine("Displaying certificate manager");
    SSLFTPCertificate.ShowCertificateManager("Please ensure that the server's certificate is installed", null);
    
    // connect to server
    PrintLine("Connecting to server " + serverAddress);
    ftpConnection.Connect();
    
    // get the current working directory and files
    PrintLine("Files in directory " + ftpConnection.ServerDirectory + ":");
    PrintLines(ftpConnection.GetFiles());
    
    // Shut down client
    PrintLine("Closing client");
    ftpConnection.Close();
    
    PrintLine("Example complete");
}

How to use FTPS (with client/server validation)

The topic How to use FTPS (introduction) describes the FTPS features of SecureFTPConnection. This topic demonstrates the use of FTPS with server validation and client authentication through client certificates.

IMPORTANT: An FTPS compatible FTP server is required for this example. You can download a free trial of CompleteFTP, a Windows FTPS server, from this link. SecureFTPConnection may be configured such that it presents a client certificate upon request from the server. Note that the server will usually only request the client certificate if it has been configured to do so. In addition, the server will validate the client certificate in a manner similar to the way the client validates the server. This is, however, a server configuration issue and will not be covered here and we will simply assume that the server is able to validate the client's certificate.

SecureFTPConnection provides visual tools for loading client certificates at design-time or at runtime. To load a certificate at runtime the SSLFTPCertificate.PromptForCertificate method should be called:


SSLFTPCertificate clientCertificate = SSLFTPCertificate.PromptForCertificate(form, <font color="#0000ff">true</font>;

This call shows appropriate dialogs for loading a certificate and a private key. Since the private key is password-protected a password prompt will also be displayed. If the flag is false then no private key will be loaded.

If no user interface is required then a certificate may be loaded as follows:


SSLFTPCertificate clientCertificate = SSLFTPCertificate.CreateFromPEM(certFileName);
clientCertificate.AssociatePrivateKey(prvKeyFileName, password);

Once a client certificate has been loaded it may be used with the SecureFTPConnection:


ftpConnection.ClientCertificate = clientCertificate;

Note that there is no need to load the client certificate into the certificate store on the machine on which SecureFTPConnection is being used.

Note also that developers often experience problems when trying to load a private key from a Windows Service. The topic, Private Key Access Problems, discusses this issue.

How to use SFTP (without server validation)

public void Run(string serverAddress, int serverPort, string userName, string password)
{
    // Create SecureFTPConnection object
    SecureFTPConnection ftpConnection = new SecureFTPConnection();
    
    // setting server address and credentials
    ftpConnection.ServerAddress = serverAddress;
    ftpConnection.ServerPort = serverPort;
    ftpConnection.UserName = userName;
    ftpConnection.Password = password;
    
    // select SFTP
    ftpConnection.Protocol = FileTransferProtocol.SFTP;
    
    // turn off server validation
    ftpConnection.ServerValidation = SecureFTPServerValidationType.None;
    
    // connect to server
    PrintLine("Connecting to server " + serverAddress);
    ftpConnection.Connect();
    
    // get the current working directory and files
    PrintLine("Files in directory " + ftpConnection.ServerDirectory + ":");
    PrintLines(ftpConnection.GetFiles());
    
    // Shut down client
    PrintLine("Closing client");
    ftpConnection.Close();
    
    PrintLine("Example complete");
}

How to use SFTP (without server validation)

The topic How to use SFTP (introduction) describes the SFTP features of SecureFTPConnection. This topic demonstrates the use of SFTP without server validation. Server validation should always be used in a production environment, but disabling it is a good way of getting started.

IMPORTANT: An SFTP compatible server is required for this example. You can download a free trial of CompleteFTP, a Windows SFTP server, from this link.

Using SFTP without server validation is simply a matter of setting the Protocol and ServerValidation properties as follows:

ftpConnection.Protocol = FileTransferProtocol.SFTP;
ftpConnection.ServerValidation = SecureFTPServerValidationType.None

The first line tells SecureFTPConnection that it is to use SFTP and the second line that it should not try to validate the server's public key.

The UserName and Password must also be set, along with the ServerAddress. Note that some SFTP servers are set up to disallow password authentication, in which case the connection attempt will fail unless password authentication is enabled in the server configuration file.

After this a secure connection is established by simply calling Connect():

ftpConnection.Connect();