Saturday, September 27, 2008

NET 2.0 FtpWebRequest class is far from perfect as self-contained class

In .NET framework 2.0, Microsoft introduced a new class for FTP- FtpWebRequest Class. This class can consider as high-level wrapper class so that developers should no longer need to deal with socket programming and FTP raw command:

  • ABOR - abort a file transfer
  • CWD - change working directory
  • DELE - delete a remote file
  • LIST - list remote files
  • MDTM - return the modification time of a file
  • MKD - make a remote directory
  • NLST - name list of remote directory
  • PASS - send password
  • PASV - enter passive mode
  • PORT - open a data port
  • PWD - print working directory
  • QUIT - terminate the connection
  • RETR - retrieve a remote file
  • RMD - remove a remote directory
  • RNFR - rename from
  • RNTO - rename to
  • SITE - site-specific commands
  • SIZE - return the size of a file
  • STOR - store a file on the remote host
  • TYPE - set transfer type
  • USER - send username
But after applying it in the real application to connect to a Unix FTP server, as a class or dll, with the reference from the sample "FTP Explorer" in MSDN, I found that I have trouble navigating to parent directory, where I would hit error:


System.Net.WebException: The remote server returned an error: (550) File unavailable (e.g., file not found, no access).

(See List of FTP server return codes) but I could do it without any problem using FileZilla. Excluding the problem might come from .NET framework, since FTP is under RFC 959, I was recommended by someone to use the WireShark, a Packet sniffer tool, to check the message sent and received between server and client.


I just realized that the FtpWebRequest class itself could not simply navigate to any path in the server if the default directory is not root path, since with WebRequestMethods.Ftp Members, you only got these raw commands that it wrapped (where's FTP CWD protocol ?):

  • FTP APPE protocol
  • FTP DELE protocol
  • FTP RETR protocol
  • FTP MDTM protocol
  • FTP SIZE protocol
  • FTP NLIST protocol
  • FTP LIST protocol
  • FTP MKD protocol
  • FTP PWD protocol
  • FTP RMD protocol
  • FTP RENAME protocol
  • FTP STOR protocol
  • FTP STOU protocol

(Even using "PrintWorkingDirectory", only empty string returned)

From Mariya Atanasova's Blog:

The above example will bring you to your user's directory and list all the contents there. Now let's say you want to go 2 directories backwards and list the contents there (provided your user has permissions to do that). You close the previous FtpWebRequest and issue a new one with this uri
uri = "
ftp://myFtpUserName:myFtpUserPassword@myFtpUrl/%2E%2E/%2E%2E";
This is equivalent to logging in with your user's credentials and then using cd ../../

But one strange thing: what if user (or even you, the developer) does not know the default directory and current directory? Then you might need WinINet Functions or even worst, go back to socket programming.

p/s: For those who prefer to have hand dirty, there's a free e-book available in scribd: TCP/IP Sockets in C# .

2 comments:

Anonymous said...

I found the same problems that you did, but I'm currently working on a solution.

To get the working directory, you have to check the StatusDescription of the FtpWebResponse.

My plan is to always ask for the working directory and then build the path relative to it, e.g. if the working folder after login is "/root" and you want list the directory "/etc", you pass in
"/%2E%2E/etc/"

gary said...

To get the working directory, you have to check the StatusDescription of the FtpWebResponse?
Really? That's sound weird! How you get that?
FtpWebResponse.StatusDescription Property(From MSDN):
The text returned by the StatusDescription property includes the 3-digit StatusCode property value. When downloading data, the value of StatusDescription changes as status codes are returned by the FTP server. After you call the GetResponse method, StatusDescription contains an intermediate status code. When you call the Close method, StatusDescription contains the final status.