Reputation: 19661
Okay, I managed -with the help of @MitchelSellers's comment- to figure out where the problem exactly is, and I'm trying to find a solution for it.
CWD
(change working directory)..NET 2.0
-for unknown reasons- it sends this command followed by /
after logging in, to change the working directory to the current working directory!! (as shown below, and I also confirmed that using FileZilla with another server). .NET
, which is why it works on .NET 4.x
.So, I'm trying to find a way to make it work on .NET 2.0
.
Here's my code:
Private Sub DownloadTestFile()
Dim filePath As String = "ftp://ftp.kohlandfrisch.com/testfile"
Dim request As FtpWebRequest
Dim buffer(1023) As Byte
Dim bytesIn As Integer
request = DirectCast(WebRequest.Create(filePath), FtpWebRequest)
request.Method = WebRequestMethods.Ftp.DownloadFile
request.Credentials = New NetworkCredential("username", "password")
request.UseBinary = False
request.UsePassive = True
request.Proxy = Nothing
Using stream As IO.Stream = request.GetResponse.GetResponseStream
Using output = IO.File.Create(localFilePath)
bytesIn = 1
Do Until bytesIn < 1
bytesIn = stream.Read(buffer, 0, 1024)
If bytesIn > 0 Then output.Write(buffer, 0, bytesIn)
Loop
End Using
End Using
End Sub
When running that code on .NET 4
or 4.x
, it works perfectly fine. However when running it on .NET 2.0
(I have to use .NET 2.0), it throws an exception when calling request.GetResponse
. Here's the exception message is:
The remote server returned an error: (501) Syntax error in parameters or arguments.
I figured out that there must be something wrong with the request sent from .NET 2.0
, so I decided to capture requests and responses using Wireshark, and my assumption was correct, but I still don't understand what the problem exactly is since I'm using the same code on both ..NET
versions
.NET 4.5.2
.NET 2.0
Any ideas?
Side note: Although my code is in VB, any answer with C# code is welcomed.
Upvotes: 3
Views: 564
Reputation: 65
Have you tried making the filePath an absolute path? i.e
Dim filePath As String = "ftp://ftp.kohlandfrisch.com/%2ftestfile"
%2f represents the / character.
This might be a workaround.
Upvotes: 0
Reputation: 70379
UPDATE according to comment:
.NET 2 does not honour that flag :-( It contains a method called BuildCommandsList() - part the source in .NET 2 looks like this:
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));
}
So basically the CWD is hardcoded in .NET 2. This leaves you with 2 undesirable "options": either make the FTP server RFC compliant (which it currently is not!) or user some other library/way to access it.
A very unusual way might be to call/automate the DOS-command ftp from your .NET application...
Left for reference:
MS has documented this change of behaviour between .NET 2 and .NET 4 here: https://support.microsoft.com/en-au/help/2134299/system.net.ftpwebrequest-class-behaves-differently-in-.net-framework-4-vs-.net-framework-3.5
I suspect that it is worth a try to remove the described flag in .NET 2.0 - something similar to this:
private static void SetMethodRequiresCWD()
{
Type requestType = typeof(FtpWebRequest);
FieldInfo methodInfoField = requestType.GetField("m_MethodInfo", BindingFlags.NonPublic | BindingFlags.Instance);
Type methodInfoType = methodInfoField.FieldType;
FieldInfo knownMethodsField = methodInfoType.GetField("KnownMethodInfo", BindingFlags.Static | BindingFlags.NonPublic);
Array knownMethodsArray = (Array)knownMethodsField.GetValue(null);
FieldInfo flagsField = methodInfoType.GetField("Flags", BindingFlags.NonPublic | BindingFlags.Instance);
int MustChangeWorkingDirectoryToPath = 0x100;
foreach (object knownMethod in knownMethodsArray)
{
int flags = (int)flagsField.GetValue(knownMethod);
flags &= (~MustChangeWorkingDirectoryToPath);
flagsField.SetValue(knownMethod, flags);
}
}
Sorry - I can't try this right now so this more like a suggestion...
EDIT: Alternatively you could use some ftp library which behaves similar to what .NET 4 does.
Upvotes: 1