2013-03-26 58 views
1

我有一個用C#(.Net 3.5)編寫的應用程序。F#FTP失敗,其中C#成功

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: The remote server returned an error: (550) File unavailable (e.g. file not found, no access).

然而,C#應用程序運行併成功下載文件。我在F#中缺少什麼(除了4.0中沒有的屬性,即KeepAlive,UsePassive和UseBinary)?

+3

爲什麼你認爲'FtpWebRequest'缺少的額外屬性?他們[there](http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest_properties%28v=vs.100%29.aspx):'ftp.KeepAlive < - true; ftp.UsePassive < - false; ftp.UseBinary < - false' – 2013-03-26 19:13:29

+0

好的。我發誓,我在兩個小時的時間內檢查了三次IntelliSense,並且這些屬性從未出現過。現在他們做到了。但是:他們沒有區別。我犯了同樣的錯誤。 – 2013-03-26 20:54:48

+2

然後當你使用主動ftp模式時,看看[這個SO](http://stackoverflow.com/questions/6251169/ftpwebrequest-net-3-5-vs-4)是有意義的。我會很快檢查你的C#在.net 4.0下是否正確,然後懷疑F#有任何錯誤。 – 2013-03-26 22:20:10

回答

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

The cause of this issue is due to a behavior change in the System.Net.FtpWebRequest class in .Net Framework 4. There has been a change made to the System.Net.FtpWebRequest class from .Net Framework 3.5 to .Net Framework 4 to streamline the use of the CWD protocol commands. The new implementation of the System.Net.FtpWebRequest class prevents the send of extra CWD commands before issuing the actual command which the user requested and instead directly sends the requested command. For fully RFC compliant FTP servers, this should not be an issue, however for non-fully RFC compliant servers, you will see these types of errors.

+0

哇!非常感謝! – 2013-03-28 13:41:29

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字符串來發現問題。

+0

我確實比較了F#和C#中的uri字符串,它們是相同的,我會發布uri字符串,但我認爲我的公司會得到因爲我發佈了它們,這就是爲什麼我將參數未定義,實名更改的原因,在我的代碼中,它們的值是通過配置文件設置的 – 2013-03-27 12:58:07

+0

我也試過System.String。格式()如你所建議的,導致相同的(正確的)uri和相同的錯誤。 – 2013-03-27 14:01:13