tags:

views:

667

answers:

9

I am designing an auto downloader using .NET and C#. I was wondering if there is a decent/robust FTP/SFTP module out there that I can use, preferably free of charge.

EDIT: I probably should've noted that I am looking for answer from somebody who tried several and found one that works very well. I currently use .NET wrapper for libcurl for FTP and it does not behave right. For example when I connect to FTP site with Filezilla and provide a path, it finds directory just fine. With libcurl, i get a header for 404 page saying path cannot be found. I am guessing that Filezilla gets 'home' directory correctly, and libcurl puts me to the root (i tried no path, and i had no permissions to access that directory). But anyways, I just don't know enough about FTP itself, so I would like something that just works.

Thanks!

A: 

The built-int WebClient class should work just fine for most scenarios.

If you need a more fine-grained control over the FTP process, a quick search on codeplex.com reveals several free FTP libraries. I haven't used any of them, so can't recommend particular one, but you should be able to find something that fits your needs relatively quickly.

Franci Penov
+2  A: 

For cheap/free FTP, you can't really beat System.Net.FtpWebRequest and System.Net.WebClient. Both come built into .net. :)

For SFTP, you might have a bit harder time.

cHao
+1  A: 

For SFTP, I've used WinSCP as a client process before (it would invoke the winscp executable and wait for the return). It's obviously not the most optimal solution though.

Tejs
+1  A: 

Take a look at FtpDLX at http://www.weonlydo.com/FtpDLX.NET/ftp.sftp.ftps.ssl.net.component.asp. It's not free but it handles FTP, SFTP (SSH), and FTPS (SSL) encryption. It's 100% managed code and works great with C#. It's also very handy to be able to use one library regardless of whether you're hitting a server on port 21 or 22.

We're using it in production and it's been a solid performer with a variety of servers.

ebpower
I've used this before, it's very simple and works great.
Tim Meers
+2  A: 

I should warn you about one-size-fits-all components. SFTP and FTP/FTPS are very different protocols, with different ideology, command sets, features etc.. Trying to fit them both into one component leads to very small set of functionality (usually common to FTP and SFTP) that you get. In other words, you can't do many things, specific to one or another protocol. The examples of such limitations are limited capabilities for server key (in SSH) or certificate (in SSL) validation, very poor (if any) control over security functions, only basic set of file operations etc. It's better to use components designed for some particular task, i.e. for FTP(S) or for SFTP. This way you have complete control over all aspects of functionality. For example, SecureBlackbox offers such components.

Eugene Mayevski 'EldoS Corp
+1  A: 

For SFTP I've had success in several projects with SharpSSH although it's obviously not a SFTP specific solution. However, the source code comes with examples and it's free so it's at least worth a look at integrating for the SFTP side of your solution.

Tom
+1  A: 

I would recommend our Rebex File Transfer Pack which support FTP, FTP/SSL, SFTP and SCP.

If you are new to the FTP check the Secure FTP, FTP/SSL, SFTP, FTPS, FTP, SCP... What's the difference? page.

Martin Vobr
Can you very blatantly disclose your involvement with the company in the shameless plug?
Tim Post
You have to be VERY careful about self-promotion on SO. See this meta question for more info http://meta.stackoverflow.com/questions/57497/limit-to-self-promotion-in-answers More often than not self promoters are going to end up doing more bad than good on SO.
Will
@Tim Post: Check my profile. I'm not hiding my involvement. I'm one of developers of that product + founder of Rebex. I'm even disclosing my connection with the company in my screen name. Such disclosure used to be considered recommended behavior (http://meta.stackoverflow.com/questions/15787/how-do-i-mention-my-own-products-in-answers) in SO in the past. And this time instead of sounding funny I've ended showing a bad taste :-(. Sorry. Sometimes it's not easy to chose the right tone for non native English speaker.@Will: Point taken, I've removed the controversial paragraph from the my post.
Martin Vobr
Thanks, Martin.
Will
A: 

As one of the developers I recommend edtFTPnet/PRO, a powerful client library supporting FTP, FTPS and SFTP. It's built on edtFTPnet, which is a very popular open source FTP library.

Bruce Blackshaw
A: 

Found in http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest.aspx

Imports System
Imports System.Collections.Generic
Imports System.Net
Imports System.IO
Imports System.Text
Imports System.Security.Cryptography.X509Certificates
Imports System.Net.Security

    Public Class FTP

        Public UserName As String = String.Empty
        Public Password As String = String.Empty
        Public KeepAlive As Boolean = False
        Public UseSSL As Boolean = True
        Public m_FTPSite As String = String.Empty

        Public Property FTPSite() As String
            Get
                Return m_FTPSite
            End Get
            Set(ByVal value As String)
                m_FTPSite = value
                If Not m_FTPSite.EndsWith("/") Then m_FTPSite += "/"
            End Set
        End Property

        Private m_CurDir As String = String.Empty
        Public Property CurrentDirectory() As String
            Get
                Return m_CurDir
            End Get
            Set(ByVal value As String)
                m_CurDir = value
                If Not m_CurDir.EndsWith("/") And m_CurDir <> "" Then
                    m_CurDir += "/"
                    m_CurDir = m_CurDir.TrimStart("/".ToCharArray())
                End If
            End Set
        End Property

        Public Sub New()
        End Sub

        Public Sub New(ByVal sFTPSite As String, ByVal sUserName As String, ByVal sPassword As String)
            UserName = sUserName
            Password = sPassword
            FTPSite = sFTPSite
        End Sub

        Public Function ValidateServerCertificate(ByVal sender As Object, ByVal certificate As X509Certificate, ByVal chain As X509Chain, ByVal sslPolicyErrors As SslPolicyErrors) As Boolean
            If sslPolicyErrors = sslPolicyErrors.RemoteCertificateChainErrors Then
                Return False
            ElseIf sslPolicyErrors = sslPolicyErrors.RemoteCertificateNameMismatch Then
                Dim z As System.Security.Policy.Zone = System.Security.Policy.Zone.CreateFromUrl(CType(sender, HttpWebRequest).RequestUri.ToString)
                If z.SecurityZone = System.Security.SecurityZone.Intranet Or z.SecurityZone = System.Security.SecurityZone.MyComputer Then
                    Return True
                End If
                Return False
            End If
            Return True
        End Function

        Public Function GetFileList(ByVal CurDirectory As String, ByVal StartsWith As String, ByVal EndsWith As String) As List(Of String)
            CurrentDirectory = CurDirectory
            Return GetFileList(StartsWith, EndsWith)
        End Function

        Public Function GetFileList(ByVal StartsWith As String, ByVal EndsWith As String) As List(Of String)
            Dim oFTP As FtpWebRequest = CType(FtpWebRequest.Create(FTPSite & CurrentDirectory), FtpWebRequest)
            oFTP.Credentials = New NetworkCredential(UserName, Password)
            oFTP.KeepAlive = KeepAlive
            oFTP.EnableSsl = UseSSL
            If UseSSL Then ServicePointManager.ServerCertificateValidationCallback = New RemoteCertificateValidationCallback(AddressOf ValidateServerCertificate)
            oFTP.Method = WebRequestMethods.Ftp.ListDirectory
            Dim response As FtpWebResponse = CType(oFTP.GetResponse, FtpWebResponse)
            Dim sr As StreamReader = New StreamReader(response.GetResponseStream)
            Dim str As String = sr.ReadLine
            Dim oList As New List(Of String)
            While str IsNot Nothing
                If str.StartsWith(StartsWith) And str.EndsWith(EndsWith) Then
                    oList.Add(str)
                    str = sr.ReadLine
                End If
            End While
            sr.Close()
            response.Close()
            oFTP = Nothing
            Return oList
        End Function

        Public Function GetFile(ByVal Name As String, ByVal DestFile As String) As Boolean
            Dim oFTP As FtpWebRequest = CType(FtpWebRequest.Create(FTPSite & CurrentDirectory & Name), FtpWebRequest)
            oFTP.Credentials = New NetworkCredential(UserName, Password)
            oFTP.Method = WebRequestMethods.Ftp.DownloadFile
            oFTP.KeepAlive = KeepAlive
            oFTP.EnableSsl = UseSSL
            If UseSSL Then ServicePointManager.ServerCertificateValidationCallback = New RemoteCertificateValidationCallback(AddressOf ValidateServerCertificate)
            oFTP.UseBinary = True
            Dim response As FtpWebResponse = CType(oFTP.GetResponse, FtpWebResponse)
            Dim responseStream As Stream = response.GetResponseStream
            Dim fs As New FileStream(DestFile, FileMode.Create)
            Dim buffer(2047) As Byte
            Dim read As Integer = 1
            While read <> 0
                read = responseStream.Read(buffer, 0, buffer.Length)
                fs.Write(buffer, 0, read)
            End While
            responseStream.Close()
            fs.Flush()
            fs.Close()
            responseStream.Close()
            response.Close()
            oFTP = Nothing
            Return True
        End Function

        Public Function UploadFile(ByVal oFile As FileInfo) As Boolean
            Dim ftpRequest As FtpWebRequest
            Dim ftpResponse As FtpWebResponse
            Try
                ftpRequest = CType(FtpWebRequest.Create(FTPSite + CurrentDirectory + oFile.Name), FtpWebRequest)
                ftpRequest.Method = WebRequestMethods.Ftp.UploadFile
                ftpRequest.Proxy = Nothing
                ftpRequest.UseBinary = True
                ftpRequest.Credentials = New NetworkCredential(UserName, Password)
                ftpRequest.KeepAlive = KeepAlive
                ftpRequest.EnableSsl = UseSSL
                If UseSSL Then ServicePointManager.ServerCertificateValidationCallback = New RemoteCertificateValidationCallback(AddressOf ValidateServerCertificate)
                Dim fileContents(oFile.Length) As Byte
                Using fr As FileStream = oFile.OpenRead
                    fr.Read(fileContents, 0, Convert.ToInt32(oFile.Length))
                End Using
                Using writer As Stream = ftpRequest.GetRequestStream
                    writer.Write(fileContents, 0, fileContents.Length)
                End Using
                ftpResponse = CType(ftpRequest.GetResponse, FtpWebResponse)
                ftpResponse.Close()
                ftpRequest = Nothing
                Return True
            Catch ex As WebException
                Return False
            End Try
        End Function

        Public Function DeleteFile(ByVal Name As String) As Boolean
            Dim oFTP As FtpWebRequest
            oFTP = CType(FtpWebRequest.Create(FTPSite + CurrentDirectory + Name), FtpWebRequest)
            oFTP.Credentials = New NetworkCredential(UserName, Password)
            oFTP.Method = WebRequestMethods.Ftp.DeleteFile
            oFTP.KeepAlive = KeepAlive
            oFTP.EnableSsl = UseSSL
            If UseSSL Then ServicePointManager.ServerCertificateValidationCallback = New RemoteCertificateValidationCallback(AddressOf ValidateServerCertificate)
            oFTP.UseBinary = True
            Dim response As FtpWebResponse = CType(oFTP.GetResponse, FtpWebResponse)
            Dim oStat As FtpStatusCode = response.StatusCode
            response.Close()
            oFTP = Nothing
            Return True
        End Function
    End Class
Chocol8