从(特定)服务器下载 FTP 文件适用于 .NET 4+,但不适用于 .NET 2.0

Download FTP file from a (specific) server works on .NET 4+, but doesn't work on .NET 2.0

更新(此问题的原因):

好的,在@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 44.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捕获请求和响应,我的假设是正确的,但我仍然不明白问题到底是什么,因为我在两个 .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 个不受欢迎的 "options":要么使 FTP 服务器 RFC 兼容(目前不兼容!),要么使用其他 library/way 来访问它。

一种非常不寻常的方法可能是从您的 .NET 应用程序 call/automate DOS-command 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。

您是否尝试过将 filePath 设置为绝对路径?即

Dim filePath As String = "ftp://ftp.kohlandfrisch.com/%2ftestfile"

%2f表示/字符。

这可能是一种解决方法。