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

时间:2017-01-25 18:18:28

标签: c# .net vb.net ftp ftpwebrequest

更新(此问题的原因):

好的,我在@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时抛出异常。这里的例外信息是:

  

远程服务器返回错误:(501)参数中的语法错误   或论据。

我发现从.NET 2.0发送的请求肯定有问题,所以我决定使用Wireshark捕获请求和响应,我的假设是正确的,但我仍然没有&#39;因为我在.NET个版本上使用相同的代码,所以我明白了问题究竟是什么。

Wireshark结果

.NET 4.5.2

Wireshark results <code>.NET 4.5.2</code>

.NET 2.0

Wireshark results <code>.NET 2.0</code>

有什么想法吗?

旁注:虽然我的代码是在VB中,但欢迎使用C#代码的任何答案。

2 个答案:

答案 0 :(得分:1)

根据评论更新:

.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个不受欢迎的&#34;选项&#34;:要么使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。

答案 1 :(得分:0)

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

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

%2f 代表 / 字符。

这可能是一种解决方法。