我使用此代码用C#(。Net 3.5)编写了一个应用程序。
using System;
using System.Net;
string strURI = String.Format("ftp://x{0}ftp/%2F'{1}'", parm1, parm2);
FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(strURI);
ftp.Proxy = null;
ftp.KeepAlive = true;
ftp.UsePassive = false;
ftp.UseBinary = false;
ftp.Credentials = new NetworkCredential("uid", "pass");
ftp.Method = WebRequestMethods.Ftp.DownloadFile;
FtpWebResponse response = (FtpWebResponse)ftp.GetResponse();
...
我已将其翻译成F#(。NET 4.0)以在我的应用程序中使用。
open System.Net
let uri = sprintf "ftp://x%sftp/%%2F'%s'" parm1 parm2
let ftp = FtpWebRequest.Create(uri) :?> FtpWebRequest
ftp.Credentials <- new NetworkCredential("uid", "pass")
ftp.Method <- WebRequestMethods.Ftp.DownloadFile
ftp.Proxy <- null
let response = ftp.GetResponse() :?> FtpWebResponse
...
此时,FSI抱怨道。
System.Net.WebException:远程服务器返回错误:(550)文件不可用(例如找不到文件,没有访问权限。)
然而,C#应用程序运行并成功下载该文件。我在F#中缺少什么(除了4.0中没有的属性,即KeepAlive,UsePassive和UseBinary)?
答案 0 :(得分:5)
代码可能有错误,我现在没有F#编译器。
open System
open System.Reflection
open System.Net
let switch_to_legacy_mode _ =
let wtype = typeof<FtpWebRequest>
let mfield = wtype.GetField("m_MethodInfo", BindingFlags.NonPublic ||| BindingFlags.Instance)
let mtype = mfield.FieldType
let knfield = mtype.GetField("KnownMethodInfo", BindingFlags.Static ||| BindingFlags.NonPublic)
let knarr = knfield.GetValue(null) :?> Array
let flags = mtype.GetField("Flags", BindingFlags.NonPublic ||| BindingFlags.Instance)
let flag_val = 0x100
for f in knarr do
let mutable ff = flags.GetValue(f) :?> int
ff <- ff ||| flag_val
flags.SetValue(f, ff)
let uri = sprintf "ftp://x%sftp/%%2F'%s'" parm1 parm2
do switch_to_legacy_mode () // Call it once before making first FTP request
let ftp = FtpWebRequest.Create(uri) :?> FtpWebRequest
ftp.Credentials <- new NetworkCredential("uid", "pass")
ftp.Method <- WebRequestMethods.Ftp.DownloadFile
ftp.Proxy <- null
let response = ftp.GetResponse() :?> FtpWebResponse
来源:http://support.microsoft.com/kb/2134299
此问题的原因是由于行为的改变 .Net Framework 4中的System.Net.FtpWebRequest类。有一个 从.Net Framework更改到System.Net.FtpWebRequest类 3.5到.Net Framework 4简化了CWD协议命令的使用。 System.Net.FtpWebRequest类的新实现 在发出实际命令之前阻止发送额外的CWD命令 用户请求的命令,而是直接发送 请求的命令。对于完全符合RFC的FTP服务器,这应该是 这不是一个问题,但对于非完全符合RFC的服务器,你会 看到这些类型的错误。
答案 1 :(得分:0)
请改为尝试:
open System
open System.Net
let parm1 = "test"
let parm2 = "othertest"
let uri = String.Format("ftp://x{0}ftp/%2F'{1}'", parm1, parm2)
let ftp = FtpWebRequest.Create(uri) :?> FtpWebRequest;;
我必须添加一个虚拟parm1和parm2,但我假设您已经在实际代码中定义了parm1和parm2。我想无论问题是什么,它都在uri字符串中。也就是说,我认为你会通过比较uri和已知的优秀uri字符串找到问题。