Implementing FTP in the .NET Framework
Introduction
Anybody with experience in Web design knows that in order to
put the site “live,” the Web page files need to be sent to a Web server
provided by your hosting company or ISP. Most people never get to see the
physical machine that their Web site is hosted on, and their only contact with
it is through a file transfer protocol, or FTP, program such as cuteFTP or smartFTP. FTP is
the most common cross-platform file transfer mechanism between computers over
the Internet. FTP software is freely available for all major operating systems,
including Windows, UNIX, and Mac OS X. This cross-platform interoperability is
very important for Web site development because most Web designers work on
Windows and most Web servers run from UNIX, Linux, and Netware OS.
FTP as defined in RFC 1350 supersedes
an older protocol known as trivial file transfer protocol (TFTP). This system
is very seldom used on the Internet, but it can be used for procedures such as
diskless booting on a net- work. It has no authentication facilities.
Implementation of FTP in .NET
Whilst .NET has good
in-built support for HTTP (web access), and SMTP (email), it does not have any
support for FTP, so in this article we show you how to do it, using standard
windows components.
There are a number of
approaches that could be taken at this point. One is to use the Internet
Transfer Control ActiveX control, which comes as standard with windows. This is
not a native .NET control, and has some known issues regarding downloading
large files using this control. Otherwise, we could develop the system up from
socket layer, using .NET’s support for TCP/IP, however, this is quite a substantial undertaking, as the
protocol is very complex at low levels. What we will use here is a freeware
.NET component, which is available from www.ftpclient.co.uk.
This component is easy to use, and reliable, from my experience.
User interface design
Open a new project in Visual Studio .NET, and draw a toolbar
on the form, add an ImageList control, and add some
icons to it – of your own choosing – for “Connect”, “Disconnect”, “Download”,
“Upload”, “Delete”, “Create Folder” and “Rename”. Set the imagelist
property of the toolbar to the ImageList, and add the
buttons as described above.
- Drop
a StatusBar, saveFileDialog,
and Treeview onto the form, calling it “Statusbar”, “saveFileDialog”
and “treeView” respectively. Now create three more
forms, named “Login”, “CreateFolder” and
“Rename”.
- On
the Login form drag three textboxes onto the form, named tbHost, tnUsername, and tbPassword. Add a button to the form, and call it btnConnect. Label the three textboxes appropriately.
- On
the create folder form, drag a text box called tbCreateFolder
onto the form, and add a button named btnCreateFolder.
Once again, label the text box appropriately
- The
rename form should look identical to the create Folder form only the text
box would be named tbRename, and the button, btnRename
As an optional extra, you can make it so that the window
stretches as the user resizes it, by adding the following code to the form’s
resize event:
void MainForm_resize(object sender, System.EventArgs e)
{
int Hedge=20;
treeView.Left=0;
treeView.Top=this.toolBar1.Height;
treeView.Width=this.Width - Hedge;
treeView.Height = this.Height-this.toolBar1.Height-this.statusBar.Height - Hedge - Hedge;
}
Initializing the FTP connection
To begin we must fist create
an instance of our FTP client component, so we place the following declaration
in the main form:
public FtpClient ftpClient = new FtpClient();
The FTP component generates
events, so to subscribe to these; we place this code in the form constructor:
public MainForm()
{
InitializeComponent();
ftpClient.FTPMessageEvent += new FtpClient.FTPMessageDelegate(Logger);
}
public void Logger(string s)
{
this.statusBar.Text=s;
}
Now, to initiate the
connection, the user will click on the connect button in the toolbar, and type
in his login details into the login dialog box – so to code this, click on the
toolbar, and add this code
void ToolBar1ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)
{
switch(e.Button.Text)
{
case "Connect":
Login frmLogin
=
new
Login();
frmLogin.parent=this;
frmLogin.ShowDialog();
TreeNode root = new TreeNode("\");
root.ImageIndex=8;
treeView.Nodes.Add(root);
treeView.SelectedNode = treeView.Nodes[0];
break;
…
We can see, from the code
above that the ShowDialog method is called, and thus
the actual connection is created in the Login dialog window. So open this, and
press the connect button, and flesh out the code as follows:
public MainForm parent;
void BtnConnectClick(object sender, System.EventArgs e)
{
string result="";
result=parent.ftpClient.connect(this.tbHost.Text,
tbUsername.Text,tbPassword.Text);
if (result!=null)
{
MessageBox.Show(result);
}
Hide();
}
Notice that this code
accounts for the possibility that connect will return a non-null value, which
could be an error message.
Navigating remote folders
Once connecting to the
server is dealt with, we can deal with listing files on the remote server; this
is done through a function, which I named populateTreeView,
which is coded thus:
public void populateTreeView(TreeNode parentNode)
{
if (parentNode==null)
{
parentNode=treeView.Nodes[0];
}
parentNode.Nodes.Clear();
ArrayList FileOrFolders;
FileOrFolders = ftpClient.getRemoteFolder(parentNode.FullPath);
foreach(FTP.RemoteFileOrFolder fileOrFolder in FileOrFolders)
{
TreeNode tnLeaf = new TreeNode(fileOrFolder.name);
if (fileOrFolder.type==FTP.FileOrFolder.FILE)
{
tnLeaf.ImageIndex=9;
}
else
{
tnLeaf.ImageIndex=8;
}
tnLeaf.Text = fileOrFolder.name;
parentNode.Nodes.Add(tnLeaf);
parentNode.ImageIndex=8;
parentNode.ExpandAll();
}
}
As you can see from the above
code, this calls the getRemoteFolder method of the
FTP component, which returns an array list of objects of type RemoteFileOrFolder. As the name suggests, this collection
contains both files and folders, and how they are displayed on-screen depends
on the type property of the object.
The user will want to
navigate the remote file system by clicking on folders, so we use this code to
respond to click events by the user
void TreeViewAfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
{
if (e.Node.ImageIndex == 8 && e.Node.Nodes.Count==0)
{
populateTreeView(e.Node);
}
}
This code simply checks that
the item clicked on was a folder, and that it’s
contents had not already been retrieved, before calling populateTreeView
again.
For completeness, a helper
function is also required by other operations, which will be discussed later.
The findNode function is used to find the parent node
of any given node, and is implemented thus:
public TreeNode findNode(TreeNode root,string fullpath)
{
foreach (TreeNode child in root.Nodes)
{
if(child.FullPath==fullpath)
{
return root;
}
TreeNode grandChildren;
grandChildren = findNode(child,fullpath);
if (grandChildren!=null)
{
return(grandChildren);
}
}
return null;
}
Uploading files
In order to upload a file, a
user will press the upload button on the toolbar, select the file to be
uploaded, and then press ok. So, to implement this, start off by clicking on
the toolbar, and add this code to the switch statement.
case "Upload":
openFileDialog.ShowDialog();
string fileUpload = openFileDialog.FileName;
ftpClient.upload(fileUpload,treeView.SelectedNode.FullPath);
populateTreeView(findNode(treeView.Nodes[0],
treeView.SelectedNode.FullPath));
break;
And that’s all there is to
it!
Downloading files
In order to download a file,
a user will select a file then press the download button on the toolbar, select
the path to where the file will be saved, and press ok. So, to implement this,
start off by clicking on the toolbar, and add this code to the switch
statement:
case "Download":
saveFileDialog.FileName = treeView.SelectedNode.Text;
saveFileDialog.ShowDialog();
string fileDownload = saveFileDialog.FileName;
ftpClient.download(treeView.SelectedNode.FullPath,
fileDownload);
populateTreeView(findNode(treeView.Nodes[0],
treeView.SelectedNode.FullPath));
break;
Renaming Files
In order to rename a file, a
user will select a file then press the rename button on the toolbar, select the
new name for the file, and press ok. So, to implement this, start off by
clicking on the toolbar, and add this code to the switch statement:
case "Rename":
RemotePath = treeView.SelectedNode.FullPath;
rename frmRename = new rename();
frmRename.parent = this;
frmRename.ShowDialog();
populateTreeView(findNode(treeView.Nodes[0],
treeView.SelectedNode.FullPath));
break;
From the code above, it is
clear that the actual rename procedure is carried out in the rename form. So,
you must also click on the rename button on the rename form, and add this code
behind it.
public MainForm parent;
void BtnRegisterClick(object sender, System.EventArgs e)
{
parent.ftpClient.rename(parent.RemotePath,tbRename.Text);
Hide();
}
Deleting files or folders
In order to delete a file or
folder, a user will select a file then press the delete button on the toolbar.
So, to implement this, start off by clicking on the toolbar, and add this code
to the switch statement:
case "Delete":
ftpClient.delete(treeView.SelectedNode.FullPath);
populateTreeView(findNode(treeView.Nodes[0],
treeView.SelectedNode.FullPath));
break;
Creating folders
In order to create a folder,
a user will select the parent folder, then press the create folder button on
the toolbar. The user then types the folder name into the dialog box, and
presses ok. So, to implement this, start off by clicking on the toolbar, and
add this code to the switch statement:
case "Create Folder":
CreateFolder frmCreateFolder = new CreateFolder();
frmCreateFolder.parent = this;
RemotePath = treeView.SelectedNode.FullPath;
frmCreateFolder.ShowDialog();
populateTreeView(findNode(treeView.Nodes[0],
treeView.SelectedNode.FullPath));
break;
Once again, the actual call
to the FTP component is carried out within the dialog window. So open the
create folder window, press the create folder button, and add this code behind
it.
public MainForm parent;
void BtnRegisterClick(object sender, System.EventArgs e)
{
parent.ftpClient.createFolder(parent.RemotePath,
tbCreateFolder.Text);
Hide();
}
Disconnecting
As a final piece of
functionality, you can add the disconnect feature. Do this by clicking on the
toolbar, and adding this code to the switch statement:
case "Disconnect":
ftpClient.disconnect();
treeView.Nodes.Clear();
break;
Conclusion
At this point the
application should be ready to run. Try it out, by connecting to your own FTP
server, or a public FTP server such as FTP.US.NERO.COM,
(username anonymous, password: anonymous). The complete version should look
similar to the screenshot below:
