更新(此问题的原因):
好吧,我在@MitchelSellers的评论的帮助下进行了管理 – 找出问题的确切位置,并且我正在努力寻找解决方案.
>显然这个服务器不允许命令CWD(更改工作目录).
>现在使用.NET 2.0下载文件 – 由于未知原因 – 它会在登录后发送此命令,然后将该工作目录更改为当前工作目录! (如下图所示,我也确认使用FileZilla与另一台服务器).
>同样如下所示,最新版本的.NET不是这种情况,这就是它适用于.NET 4.x的原因.
所以,我正试图找到一种方法使它在.NET 2.0上运行.
原来的问题:
这是我的代码:
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
在.NET 4或4.x上运行该代码时,它可以正常工作.但是,当在.NET 2.0上运行它(我必须使用.NET 2.0)时,它会在调用request.GetResponse时抛出异常.这是异常消息:
The remote server returned an error: (501) Syntax error in parameters
or arguments.
我发现从.NET 2.0发出的请求肯定有问题,所以我决定使用Wireshark捕获请求和响应,我的假设是正确的,但我仍然不明白问题究竟是什么,因为我’ m在两个.NET版本上使用相同的代码.
Wireshark结果
.NET 4.5.2
.NET 2.0
有任何想法吗?
旁注:尽管我的代码是在VB中,但欢迎使用C#代码的任何答案.
最佳答案 根据评论更新:
.NET 2不尊重该标志:-(
它包含一个名为BuildCommandsList()的方法 – 部分.NET 2中的源代码如下所示:
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));
}
所以基本上CWD在.NET 2中是硬编码的.
这将为您留下2个不受欢迎的“选项”:要么使FTP服务器符合RFC(当前不是!),要么使用其他一些库/方式来访问它.
一种非常不寻常的方式可能是从.NET应用程序调用/自动化DOS命令ftp …
留待参考:
MS在此记录了.NET 2和.NET 4之间的这种行为变化:https://support.microsoft.com/en-au/help/2134299/system.net.ftpwebrequest-class-behaves-differently-in-.net-framework-4-vs-.net-framework-3.5
我怀疑在.NET 2.0中删除描述的标志值得尝试 – 类似于:
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);
}
}
对不起 – 我现在不能尝试这个,所以这更像是一个建议……
编辑:
或者你可以使用一些ftp库,它的行为类似于.NET 4.