4
votes

I am having a problem renaming a FTP file using the following code:

    Dim Request As FtpWebRequest = DirectCast(WebRequest.Create(New Uri("ftp://sftp.mycompany.com/myfile.txt")), FtpWebRequest)
    'Set that we will be renaming a file
    Request.Method = WebRequestMethods.Ftp.Rename
    'Provide the new filename
    Request.RenameTo = NewFileName
    'The credentials needed to log onto the server
    Request.Credentials = New NetworkCredential("username", "password")
    'We are going to enable SSL for the communication with the FTP server as required by the remote server.
    Request.EnableSsl = True
    Request.UsePassive = True
    Request.KeepAlive = False
    'Create a Response object getting the downloaded file
    Dim Response As FtpWebResponse = DirectCast(Request.GetResponse(), FtpWebResponse)
    Response.Close()

I never actually had it working or needed renaming an FTP file until .NET 4.0 so that was the 1st code I wrote. A close derivitave of this code to download the file WORKS so it is not an SSL or FTP issue (read on for tracing detail) Apparently though this code was documented to work in Framework 3.5 or prior. In VS.NET 2010 .NET Framework 4.0 project I always get back: "The remote server returned an error: (550) File unavailable (e.g., file not found, no access)."

Guess what... copied the exact code into an old VS.NET 2008 test project ran it again -> worked perfectly!

So I thought I would just wrap this code up in a binary targeting the 3.5 Framework and then reference it in my VS.NET 2010 project to outsmart the bug, but it did not work.

I tried adding a workaround I found stating to add the prefix "%2E/" to the filename did not work for me. My trace log kept outputting the same results:

System.Net Information: 0 : [2228] FtpControlStream#15409429 - Received response [257 "/users/company" is current directory]
System.Net Information: 0 : [2228] FtpControlStream#15409429 - Sending command [RNFR /myfile.txt]
System.Net Information: 0 : [2228] FtpControlStream#15409429 - Received response [550 File /myfile.txt not found]

VS.NET 2008 has different results ommiting the 1st slash before the rename file:

System.Net Information: 0 : [6460] FtpControlStream#40715158 - Received response [257 "/users/company" is current directory]
System.Net Information: 0 : [6460] FtpControlStream#40715158 - Sending command [CWD /users/company/]
System.Net Information: 0 : [6460] FtpControlStream#40715158 - Received response [250 Command CWD succeed]
System.Net Information: 0 : [6460] FtpControlStream#40715158 - Sending command [RNFR myfile.txt]
System.Net Information: 0 : [6460] FtpControlStream#40715158 - Received response [350 Enter new name]
System.Net Information: 0 : [6460] FtpControlStream#40715158 - Sending command [RNTO myfileOLD.txt]
System.Net Information: 0 : [6460] FtpControlStream#40715158 - Received response [250 Renamed]

I have tried every combination and can't get this working, except when running in VS.NET 2008 or prior. This does sound like a bug or an undocumented procedure change that probably warrants an entry on connect.microsoft.com.

Any help or suggestions on this?

Thanks!

3

3 Answers

3
votes

I saw this quote in a forum

If the URI is of the form "ftp://contoso.com/%2fpath" (%2f is an escaped '/'), then the URI is absolute, and the current directory is /path.'

I had something like this:

Dim _request As FtpWebRequest = DirectCast(WebRequest.Create(New Uri("ftp://xxx.xxx.xxx.xx/%2fremotedirectory/filename.txt")), FtpWebRequest)

I wanted to move the file to remotedirectory/archive/filename.txt

so once I made the ftp request I was in the remotedirectory directory so I was therefore able to accomplish my goal like this:

_request.RenameTo = "/archive/filename.txt"

and I no longer got the 550 error.

2
votes

The answer described above wasn't working for me. Neither did these work for me:

What actually happened in my case that the complete path where I wanted my file moved to was added to the old path as if was a relative location from the files current location. e.g. I have a file at ftp://127.0.0.1/usr/john/temp/file.fmf and I want to move it to ftp://127.0.0.1/usr/mary/archive/file.fmf. I used (and this this worked in .Net Framework 3.5 and before):

        FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://127.0.0.1/usr/john/temp/file.fmf"));
        ftp.Credentials = new NetworkCredential(this.UserName, this.Password);
        ftp.KeepAlive = true;
        ftp.UsePassive = true;
        ftp.Method = WebRequestMethods.Ftp.Rename;

        ftp.RenameTo = "usr/mary/archive/file.fmf";

        ftp.UseBinary = true;
        FtpWebResponse response = (FtpWebResponse)ftp.GetResponse();

But not in .Net Framework 4.0. In the System.Net trace I found I was trying to replace the file to usr/john/temp/usr/mary/archive/file.fmf. This location didn't exist indeed. So I changed the RenameTo into a relative path:

        ftp.RenameTo = "../../mary/archive/file.fmf";

And again, the file was moved to it new location.

Although I see this merely as work around, not as solution and although I have no idea to really solve it, I am glad it is working again.

1
votes

Ok I have a work around. As you could see the VS.NET 2008 version also issues a change directory command: "CWD /users/company/" that is not isuued in VS.NET 2010 version. The undocumented (at least from what I read) but workable solution is to use the /%2f escape characters in the request URI ONLY between the folders that are resolved to as the current directory when logging onto the server. Essentially I had to be explicit and give an absolute path, using these special escape characters only between the default folders locations. The new URL request line of code is as follows below:

Dim Request As FtpWebRequest = DirectCast(WebRequest.Create(New Uri("ftp://sftp.mycompany.com/%2fusers/%2fcompany/myfile.txt")), FtpWebRequest)

I believe this is probably only a problem that will occur for those of you that log onto FTP servers, where you are resolved to a default directory automatically, and may not even provide that directory in the request URI.