ASP.NET FTP with SSL

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.



About the Author

Jereme Guenther

I love programming, I am 24 and have been programming since I was 12. I am currently a database programmer with a wife and three kids. I also have a passion for Star Wars as well as other high tech science fiction stuff. I have a personal website at: Guent her Web Design

Comments

  • Awesome -

    Posted by Mike on 07/02/2013 02:25am

    Have been looking for assistance with this all over the place, tried open source tools and coudnt get any things to work and this was straight in an working. I can get on with work again Thanks

    Reply
  • Thank you!

    Posted by Jay on 04/05/2013 08:02am

    You rock! Got your code working with little effort.

    • Please share

      Posted by Cindy on 06/12/2014 12:03pm

      Can you please share your working code. Thanks

      Reply
    Reply
  • Goal

    Posted by snareenactina on 11/08/2012 06:52am

    In short, the next level of the maturation of farming in rural developing nations like Cambodia would likely be very similar to how American farmers farmed in the early 1930’s. During that time farmers used simple and affordable mechanization tools to greatly increase efficiencies while using what is today called “organic” farming methods in regards to fertilizers and soil amendments. Additionally, many farming communities banded together to form “co-ops” to address the needs of capital formation to assemble larger infrastructure items such as crop storage and distribution systems. I understand this process and such fundamental approaches to an agricultural based business. satregional This is the flip side of the nation's oil and natural gas boom. Although the expansion of drilling has breathed economic life into many small Oklahoma towns, the lucrative opportunities are also drawing people away from traditional service-sector jobs and even once-coveted state positions. prague plannsra popcornd compressing dneek

    Reply
  • potential problem

    Posted by Joshua Rice on 08/09/2012 03:18pm

    I found a potential problem with this. I know this is old, but this post was the most helpful that I found when researching this subject. I just wanted to point out that the SslPolicyErrors is a set of enumerated flags. In the ValidateServerCertificate function, the IF statements should use the bitwise AND operation to check for flags. E.G.(sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) == SslPolicyErrors.RemoteCertificateChainErrors When I tested as the code is here, it allowed for an unencrypted response if there were multiple errors masking SslPolicyErrors.

    Reply
  • Medium trust?

    Posted by vineld on 03/25/2009 10:30am

    This seems like a great class. However, I tried it out at a web host that runs .NET under medium trust and I get a security error. Is it even possible to run it under medium trust?

    • What is the error?

      Posted by jereme.guenther on 03/25/2009 09:45pm

      I have not tried running it with .NET in medium trust. What is the error you are getting?

      Reply
    Reply
  • Thank you!

    Posted by johny555 on 01/06/2009 07:59am

    Thank you very much for this. The only thing i did not know before, is that .Net only supports "implicit FTP SSL". If you are using filezilla, configure it that way. Otherwise you might fall into the same trap as me.

    • Reply

      Posted by DavidLLLL on 10/29/2009 05:47pm

      Actually .net only supports explicit

      Reply
    Reply
  • As you said

    Posted by the__phoenix on 05/23/2008 05:54am

    There aren't very much articels on this topic and the code sample @ msdn is buggy, so thank you very much for this piece of code. It helped me save alot of time. Greetings

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Hybrid cloud platforms need to think in terms of sweet spots when it comes to application platform interface (API) integration. Cloud Velocity has taken a unique approach to tight integration with the API sweet spot; enough to support the agility of physical and virtual apps, including multi-tier environments and databases, while reducing capital and operating costs. Read this case study to learn how a global-level Fortune 1000 company was able to deploy an entire 6+ TB Oracle eCommerce stack in Amazon Web …

  • Corporate e-Learning technology has a long and diverse pedigree. As far back as the 1980s, companies were adopting computer-based training to supplement traditional classroom activities. More recently, rich web-based applications have added streaming audio and video, real-time collaboration and other new tools to the e-Learning mix. At the same time, the growing availability of informal learning tools--a category that includes everything from web searches to social media posts--are having a major impact on …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds