Question

I'm trying to get the following code working:

  string url = String.Format(@"SOMEURL");
  string user = "SOMEUSER";
  string password = "SOMEPASSWORD";

  FtpWebRequest ftpclientRequest = (FtpWebRequest)WebRequest.Create(new Uri(url));
  ftpclientRequest.Method = WebRequestMethods.Ftp.ListDirectory;
  ftpclientRequest.UsePassive = true; 
  ftpclientRequest.Proxy = null;
  ftpclientRequest.Credentials = new NetworkCredential(user, password);
  FtpWebResponse response = ftpclientRequest.GetResponse() as FtpWebResponse;

This normally works, but for 1 particular server this gives an Error 500: Syntax not recognized. The Change Directory command is disabled on the problem server, and the site administrator told me that .NET issues a Change Directory command by default with all FTP connections. Is that true? Is there a way to disable that?
EDIT: When I login from a command line I am in the correct directory:
ftp> pwd
257 "/" is current directory

Was it helpful?

Solution

I just tested this on one of our dev servers and indeed there is a CWD issued by the .NET FtpWebRequest:

new connection from 172.16.3.210 on 172.16.3.210:21 (Explicit SSL)
hostname resolved : devpc
sending welcome message.
220 Gene6 FTP Server v3.10.0 (Build 2) ready...
USER testuser
testuser, 331 Password required for testuser.
testuser, PASS ****
testuser, logged in as "testuser".
testuser, 230 User testuser logged in.
testuser, OPTS utf8 on
testuser, 501 Please CLNT first.
testuser, PWD
testuser, 257 "/" is current directory.
testuser, CWD /
testuser, change directory '/' -> 'D:\testfolder' --> Access allowed.
testuser, 250 CWD command successful. "/" is current directory.
testuser, TYPE I
testuser, 200 Type set to I.
testuser, PORT 172,16,3,210,4,127
testuser, 200 Port command successful.
testuser, NLST
testuser, 150 Opening data connection for directory list.
testuser, 226 Transfer ok.
testuser, 421 Connection closed, timed out.
testuser, disconnected. (00d00:05:01)

This was without even specifying '/' in the uri when creating the FtpWebRequest object.

If you debug or browse the source code, a class called 'FtpControlStream' comes into play. See call stack:

System.dll!System.Net.FtpControlStream.BuildCommandsList(System.Net.WebRequest req) Line 555    C#
System.dll!System.Net.CommandStream.SubmitRequest(System.Net.WebRequest request = 
    {System.Net.FtpWebRequest}, bool async = false, bool readInitalResponseOnConnect = true) Line 143   C#
System.dll!System.Net.FtpWebRequest.TimedSubmitRequestHelper(bool async) Line 1122 + 0x13 bytes C#
System.dll!System.Net.FtpWebRequest.SubmitRequest(bool async = false) Line 1042 + 0xc bytes C#
System.dll!System.Net.FtpWebRequest.GetResponse() Line 649  C#

There's a method named BuildCommandsList() which is invoked. BuildCommandsList() builds a list of commands to send to the FTP server. This method has the following snippet of code:

if (m_PreviousServerPath != newServerPath) { 
    if (!m_IsRootPath
        && m_LoginState == FtpLoginState.LoggedIn
        && m_LoginDirectory != null)
    { 
        newServerPath = m_LoginDirectory+newServerPath;
    } 
    m_NewServerPath = newServerPath; 

    commandList.Add(new PipelineEntry(FormatFtpCommand("CWD", newServerPath), PipelineEntryFlags.UserCommand)); 
}

Upon the first connection to the server m_PreviousServerPath is always null, the value of newServerPath is "/" and is computed by a function named GetPathAndFileName() (invoked a few lines prior to this block of code). GetPathAndFileName() computes newServerPath as "/" if no path is supplied or if "/" is explicitly tacked on the end of the 'ftp://....' uri.

So this of course ultimately causes the CWD command to be added to the command pipeline because null != "/".

In a nutshell unfortunately you can't override this behaviour because it's burned in the source.

OTHER TIPS

Though the post is like long time ago... never mind, I'll provide the answer here.

Instead of using ftp://server/path as the uri, try ftp://server/%2fpath/.

The added %2f" is just an escaped /, adding this will make C# treat the whole path as absolute. Or else C# will login to ftp://server/ with the username, go to the user's home folder, then cd to your specified path, so your path become user_home_path/path, which may not be desirable.

More info could be found at msdn http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest.aspx

Hope this helps.

I think we had a similar issue a while back, I don't remember the exact details though.

To prevent .net from issuing the cd command, see if setting the default directory for the user you're login in as is set to the directory you want to work in. You can just use a command line ftp client to check this out.

Here is a solution: use this free, open source, FTP Client Library for C# made by Dan at C-SharpCorner.com: http://www.c-sharpcorner.com/uploadfile/danglass/ftpclient12062005053849am/ftpclient.aspx

Here is some example code for uploading a file:

FtpClient ftp = new FtpClient(FtpServer,FtpUserName,FtpPassword);
ftp.Login();
ftp.Upload(@"C:\image.jpg");
ftp.Close(); 

This library works fine out of the box, but can also easily be extended and modified.

Using the info above, this worked for me.

Sends CWD - ftpState.ftpRequest = GetRequest("ftp://192.168.0.2/tmp/file2download")

Does not send CWD - ftpState.ftpRequest = GetRequest("ftp://192.168.0.2//tmp/file2download") notice the // after the server IP (or name)

DotNET version 2.0

Private Function GetRequest(ByVal URI As String) As FtpWebRequest
    'create request
    Dim result As FtpWebRequest = CType(FtpWebRequest.Create(URI), FtpWebRequest)
    Return result
End Function
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top