I recently needed to connect to a remote FTP server using SSL and C#.NET. I discovered that there were few good examples on the web pertaining to FTP. Part of this was because the .NET framework didn’t seem to support FTP very well until version 2.0. Even in version 2.0, it gives only the raw tools needed to put together a basic FTP client; it doesn’t have any upload, download, and the like pre-written.
After spending about a day browsing the web and cobbling together a class that acted as a sort of wrapper to give me something easier to work with, I thought I would share it. Although I did find one good example for uploading and one good example for deleting files on an FTP server, I couldn’t find one complete source that had it all. Also, I couldn’t find any source that had a working SSL implementation.
What I have here is a very rough starter class that has just passed the first phase of testing. I intend it only to help others get up and running; if you are planning on using it, it really needs a lot more error checking and features. Hopefully, I will have time later to come back and update this article with some more solid code.
using System; using System.Collections.Generic; using System.Text; using System.Net; using System.IO; using System.Security.Cryptography.X509Certificates; using System.Net.Security; namespace FtpFramework { public class FTP { public string UserName = ""; public string Password = ""; public bool KeepAlive = false; public bool UseSSL = true; private string m_FTPSite = ""; public string FTPSite { get { return m_FTPSite; } set { m_FTPSite = value; if (!m_FTPSite.EndsWith("/")) m_FTPSite += "/"; } } private string m_CurDir = ""; public string CurrentDirectory { get { return m_CurDir; } set { m_CurDir = value; if (!m_CurDir.EndsWith("/") && m_CurDir != "") m_CurDir += "/"; m_CurDir = m_CurDir.TrimStart("/".ToCharArray()); } } public FTP() { } public FTP(string sFTPSite, string sUserName, string sPassword) { UserName = sUserName; Password = sPassword; FTPSite = sFTPSite; } public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors) { return false; } else if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNameMismatch) { System.Security.Policy.Zone z = System.Security.Policy.Zone.CreateFromUrl (((HttpWebRequest)sender).RequestUri.ToString()); if (z.SecurityZone == System.Security.SecurityZone.Intranet || z.SecurityZone == System.Security.SecurityZone.MyComputer) { return true; } return false; } return true; } public List<string> GetFileList(string CurDirectory, string StartsWith, string EndsWith) { CurrentDirectory = CurDirectory; return GetFileList(StartsWith, EndsWith); } public List<string> GetFileList(string StartsWith, string EndsWith) { FtpWebRequest oFTP = (FtpWebRequest)FtpWebRequest.Create(FTPSite + CurrentDirectory); //oFTP.EnableSsl = true; oFTP.Credentials = new NetworkCredential(UserName, Password); oFTP.KeepAlive = KeepAlive; oFTP.EnableSsl = UseSSL; // Validate the server certificate with // ServerCertificateValidationCallBack if (UseSSL) ServicePointManager. ServerCertificateValidationCallback = new RemoteCertificateValidationCallback (ValidateServerCertificate); //System.Security.Cryptography.X509Certificates. //X509Certificate oCert = new System.Security.Cryptography. //X509Certificates.X509Certificate(); //oFTP.ClientCertificates.Add(oCert); oFTP.Method = WebRequestMethods.Ftp.ListDirectory; FtpWebResponse response = (FtpWebResponse)oFTP.GetResponse(); StreamReader sr = new StreamReader(response.GetResponseStream()); string str = sr.ReadLine(); List<string> oList = new List<string>(); while (str != null) { if (str.StartsWith(StartsWith) && str.EndsWith(EndsWith)) oList.Add(str); str = sr.ReadLine(); } sr.Close(); response.Close(); oFTP = null; return oList; } public bool GetFile(string Name, string DestFile) { //1. Create a request: must be in ftp://hostname format, // not just ftp.myhost.com FtpWebRequest oFTP = (FtpWebRequest)FtpWebRequest. Create(FTPSite + CurrentDirectory + Name); //oFTP.EnableSsl = true; //2. Set credentials oFTP.Credentials = new NetworkCredential(UserName, Password); //Define the action required (in this case, download // a file) oFTP.Method = WebRequestMethods.Ftp.DownloadFile; //3. Settings oFTP.KeepAlive = KeepAlive; oFTP.EnableSsl = UseSSL; // Validate the server certificate with // ServerCertificateValidationCallBack if (UseSSL) ServicePointManager. ServerCertificateValidationCallback = new RemoteCertificateValidationCallback (ValidateServerCertificate); //we want a binary transfer, not textual data oFTP.UseBinary = true; //4. If we were using a method that uploads data; // for example, UploadFile, we would open the // ftp.GetRequestStream here an send the data //5. Get the response to the Ftp request and the // associated stream FtpWebResponse response = (FtpWebResponse)oFTP.GetResponse(); Stream responseStream = response.GetResponseStream(); //loop to read & write to file FileStream fs = new FileStream(DestFile, FileMode.Create); Byte[] buffer = new Byte[2047]; int read = 1; while (read != 0) { read = responseStream.Read(buffer, 0, buffer.Length); fs.Write(buffer, 0, read); } //see Note(1) responseStream.Close(); fs.Flush(); fs.Close(); responseStream.Close(); response.Close(); oFTP = null; return true; } public bool UploadFile(FileInfo oFile) { FtpWebRequest ftpRequest; FtpWebResponse ftpResponse; try { //Settings required to establish a connection with //the server ftpRequest = (FtpWebRequest)FtpWebRequest. Create(FTPSite + CurrentDirectory + oFile.Name); ftpRequest.Method = WebRequestMethods.Ftp.UploadFile; ftpRequest.Proxy = null; ftpRequest.UseBinary = true; ftpRequest.Credentials = new NetworkCredential(UserName, Password); ftpRequest.KeepAlive = KeepAlive; ftpRequest.EnableSsl = UseSSL; // Validate the server certificate with // ServerCertificateValidationCallBack if (UseSSL) ServicePointManager. ServerCertificateValidationCallback = new RemoteCertificateValidationCallback (ValidateServerCertificate); //Selection of file to be uploaded byte[] fileContents = new byte[oFile.Length]; //will destroy the object immediately after being used using (FileStream fr = oFile.OpenRead()) { fr.Read(fileContents, 0, Convert.ToInt32(oFile.Length)); } using (Stream writer = ftpRequest.GetRequestStream()) { writer.Write(fileContents, 0, fileContents.Length); } //Gets the FtpWebResponse of the uploading operation ftpResponse = (FtpWebResponse)ftpRequest.GetResponse(); //Display response //Response.Write(ftpResponse.StatusDescription); ftpResponse.Close(); ftpRequest = null; return true; } catch (WebException webex) { return false; //this.Message = webex.ToString(); } } public bool DeleteFile(string Name) { //1. Create a request: must be in ftp://hostname format, // not just ftp.myhost.com FtpWebRequest oFTP = (FtpWebRequest)FtpWebRequest. Create(FTPSite + CurrentDirectory + Name); //oFTP.EnableSsl = true; //2. Set credentials oFTP.Credentials = new NetworkCredential(UserName, Password); //Define the action required (in this case, download a file) oFTP.Method = WebRequestMethods.Ftp.DeleteFile; //3. Settings oFTP.KeepAlive = KeepAlive; oFTP.EnableSsl = UseSSL; // Validate the server certificate with // ServerCertificateValidationCallBack if (UseSSL) ServicePointManager. ServerCertificateValidationCallback = new RemoteCertificateValidationCallback (ValidateServerCertificate); //we want a binary transfer, not textual data oFTP.UseBinary = true; //4. If we were using a method that uploads data; // for example, UploadFile, we would open the // ftp.GetRequestStream here an send the data //5. Get the response to the Ftp request and the associated // stream FtpWebResponse response = (FtpWebResponse)oFTP.GetResponse(); FtpStatusCode oStat = response.StatusCode; response.Close(); oFTP = null; return true; } // DeleteFile() } }
I would also like to give credit to the sites I got large chunks of this code from. Hopefully, if my code doesn’t make enough sense, you can use these other sites to help out. This site details uploading a file to an FTP server: http://wiki.asp.net/page.aspx/283/uploading-file-using-ftpwebrequest/.
This site details downloading a file from an FTP server: http://www.eggheadcafe.com/community/aspnet/14/80938/use-ftpwebrequest-to-down.aspx.
This site is what finally helped me figure out SSL, although I don’t think their code actually works because it isn’t an example but a request for help: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=722414&SiteID=1.