Search code examples
c#ftpdirectory-listing

How to get all sub directories under a directory using uribuilder


Trying to create an UriBuilder that will list all the subdirectories for later use.

I have tried the examples from Microsoft for this process and tried using the directory.getdirectory method without success.

String result = String.Empty;
Search searchResults = new Search();

try
{
    UriBuilder uriBuilder = new UriBuilder();
    uriBuilder.Scheme = "ftp";
    uriBuilder.Host = "ftp.myfilepath.com/public/doc";
    FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uriBuilder.Uri);

    request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;

    FtpWebResponse response = (FtpWebResponse)request.GetResponse();

    Stream responseStream = response.GetResponseStream();
    StreamReader reader = new StreamReader(responseStream);
    Console.WriteLine(reader.ReadToEnd());

    Console.WriteLine($"Directory List Complete, status {response.StatusDescription}");

    reader.Close();
    response.Close();
    result = reader.ReadToEnd();

    if (result != null)
    {
        searchResults.Messages = result;
    }
}
catch (Exception ex)
{
    searchResults.Messages = "File not found.";
} 

I want it to list out the directories found under path given by the UriBuilder. The result always comes up empty and I don't understand why or what it is I am missing.


Solution

  • Problem

    Disregarding few syntax errors (missing keyword var or type declaration on the lines 18 and 22), your code is working properly. The only problem is that you're calling reader.ReadToEnd() twice and moreover, the second call is just after you explicitly closed both the ResponseStream and StreamReader.

    The first call is on the line 12 which prints the directory listing to the console:

    Console.WriteLine(reader.ReadToEnd());
    

    And the second call is on the line 18, where you're trying to get its return value into a variable result:

    result = reader.ReadToEnd();
    

    But it's just after you closed both the ResponseStream and StreamReader:

    reader.Close();
    response.Close();
    result = reader.ReadToEnd();
    

    So you even get an error message which is explaining what you're doing wrong:

    Cannot read from a closed TextReader.

    It's an exception thrown on the line 18.

    Even if you would move both calls to the Close() methods after the line 18, it won't work anyway, because the first call to the reader.ReadToEnd() method empties the reading buffer and disposes the NetworkStream object, so there would be the following exception thrown on the line 18:

    Cannot access a disposed object. Object name: 'System.Net.Sockets.NetworkStream'.

    Solution

    What you need to do is to call the method reader.ReadToEnd() just once, do it before you close both the ResponseStream and the StreamReader and store its return value in a variable. Then, you can do whatever you want with the result:

    var uriBuilder = new UriBuilder();
    uriBuilder.Scheme = "ftp";
    uriBuilder.Host = "ftp.myfilepath.com/public/doc";
    var request = (FtpWebRequest)WebRequest.Create(uriBuilder.Uri);
    
    request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
    
    var response = (FtpWebResponse)request.GetResponse();
    
    var responseStream = response.GetResponseStream();
    var reader = new StreamReader(responseStream);
    var result = reader.ReadToEnd();
    
    Console.WriteLine(result);
    Console.WriteLine($"Directory List Complete, status {response.StatusDescription}");
    
    reader.Close();
    response.Close();
    

    Working example

    The following code has to be working if you do everything exactly as suggested:

    1. create a new solution in Visual Studio containing a console application project, use the .NET Framework 4.7.2
    2. put the following code into Program.cs:

      using System;
      using System.IO;
      using System.Net;
      
      namespace FtpDirectoryListing
      {
          class Program
          {
              static void Main(string[] args)
              {
                  var uriBuilder = new UriBuilder();
                  uriBuilder.Scheme = "ftp";
                  uriBuilder.Host = "speedtest.tele2.net";
                  var request = (FtpWebRequest)WebRequest.Create(uriBuilder.Uri);
      
                  request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
      
                  var response = (FtpWebResponse)request.GetResponse();
      
                  var responseStream = response.GetResponseStream();
                  var reader = new StreamReader(responseStream);
                  var result = reader.ReadToEnd();
      
                  Console.WriteLine(result);
                  Console.WriteLine($"Directory List Complete, status {response.StatusDescription}");
      
                  reader.Close();
                  response.Close();
              }
          }
      }
      
    3. Run it

    4. Share any potential errors it generates with us