Search code examples
c#ftpftp-clientftpwebrequestftp-server

Unknown command FEAT when accessing FTP server


I just created an FTP server based on the code provided here http://www.codeguru.com/csharp/csharp/cs_network/sockets/article.php/c7409/A-C-FTP-Server.htm . Then I installed Nuget packages for FtpClient, so that I can create a test FTP client which connects to FTP server. Following is my code:

[TestMethod]
    async public Task TestMethod1() // wanted to make it async as I may connect have something related to database in future
    {
        var client = new FtpClient
        {
            Host = "127.0.0.1",
            Port = 21,
            Credentials = new NetworkCredential
            {
                UserName = "123",
                Password = "123",
            },
            DataConnectionType = FtpDataConnectionType.PASV // If I don't add this, I get EPSV unknown command
        };

        await client.ConnectAsync();
        Debug.WriteLine("Connected");

        client.SetWorkingDirectory(@"C:\Users\myname\Desktop");
        Debug.WriteLine(client.GetWorkingDirectory());

        try
        {
            var items = client.GetListing(); // Exception shows up here.
            Debug.WriteLine(items.Count());
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
}

The issue could be that I don't have a command handler for FEAT in my server. But, my FTP server runs completely fine with filezilla. If command handler is required, can someone provide me code for this?

If I ignore this error, I get this exception in test method "Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host."

Any ideas?

[EDIT] Here's the full exception:

Test method Blackhawk.Core.FtpServer.Test.UnitTest1.TestMethod1 threw exception: 
System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. --->        System.Net.Sockets.SocketException: An existing connection was forcibly closed   by the remote host
    at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
   at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
 --- End of inner exception stack trace ---
     at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
   at    System.Net.FtpClient.FtpSocketStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at System.Net.FtpClient.FtpSocketStream.ReadLine(Encoding encoding)
   at System.Net.FtpClient.FtpClient.GetReply()
   at System.Net.FtpClient.FtpClient.Execute(String command)
   at System.Net.FtpClient.FtpClient.OpenPassiveDataStream(FtpDataConnectionType type, String command, Int64 restart)
   at System.Net.FtpClient.FtpClient.OpenDataStream(String command, Int64 restart)
   at System.Net.FtpClient.FtpClient.GetListing(String path, FtpListOption options)
   at System.Net.FtpClient.FtpClient.GetListing(String path)
   at Blackhawk.Core.FtpServer.Test.UnitTest1.<TestMethod1>d__2.MoveNext() in UnitTest1.cs: line 44
 --- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()

Solution

  • I was able to solve the problem by changing data connection type to AutoActive. Here's the final code which works:

    [TestMethod]
        async public Task FtpTestUser1()
        {
            var client = new FtpClient
            {
                Host = "127.0.0.1",
                Port = 21,
                Encoding = System.Text.Encoding.Default,
                Credentials = new NetworkCredential
                {
                    // Storing username, password and default directory in a .dat file
                    UserName = "123", 
                    Password = "123",
                },
                DataConnectionType = FtpDataConnectionType.AutoActive // Changed this part.
            };
    
            await client.ConnectAsync();
            Debug.WriteLine("Connected");
    
            var path = @"Test"; // This path is now relative to the default directory
    
            client.SetWorkingDirectory(path);
            Debug.WriteLine(client.GetWorkingDirectory());
    
    
            var items = client.GetListing();
            Assert.IsTrue(items.Any());
            Debug.WriteLine(items.Count());
    
            foreach (var ftpListItem in items)
            {
                Debug.WriteLine(string.Format("File name is {0}", ftpListItem.Name));
            }        
        }