Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/google-sheets/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Http 从C#移植到F时System.Net.WebException#_Http_F#_Httpwebresponse_C# To F# - Fatal编程技术网

Http 从C#移植到F时System.Net.WebException#

Http 从C#移植到F时System.Net.WebException#,http,f#,httpwebresponse,c#-to-f#,Http,F#,Httpwebresponse,C# To F#,我正在尝试将一些C代码移植到F C#代码取自此处(稍微向后剥离): public bool登录(字符串p12CertificateLocation、字符串p12CertificatePassword、字符串用户名、字符串密码) { var appKey=“appKey”; string postData=string.Format(“用户名={0}&密码={1}”,用户名,密码); X509Certificate2 x509certificate=新的X509Certificate2(P12证书

我正在尝试将一些C代码移植到F

C#代码取自此处(稍微向后剥离):

public bool登录(字符串p12CertificateLocation、字符串p12CertificatePassword、字符串用户名、字符串密码)
{
var appKey=“appKey”;
string postData=string.Format(“用户名={0}&密码={1}”,用户名,密码);
X509Certificate2 x509certificate=新的X509Certificate2(P12证书位置,P12证书密码);
HttpWebRequest请求=(HttpWebRequest)WebRequest.Create(“https://identitysso.betfair.com/api/certlogin");
request.UseDefaultCredentials=true;
request.Method=“POST”;
request.ContentType=“application/x-www-form-urlencoded”;
request.Headers.Add(“X-Application”,appKey);
request.ClientCertificates.Add(x509certificate);
request.Accept=“*/*”;
使用(Stream=request.GetRequestStream())
使用(StreamWriter=newstreamwriter(stream,Encoding.Default))
writer.Write(postData);
使用(Stream Stream=((HttpWebResponse)request.GetResponse()).GetResponseStream())
使用(StreamReader=newstreamreader(stream,Encoding.Default))
上面的C#代码工作得很好。但是,当尝试运行(我认为是)F#等效代码时,在没有任何实际修改的情况下,我会收到一条错误消息

代码在同一台计算机上运行,与VS安装相同,并且具有完全相同的4个参数

我收到的错误消息位于倒数第二行:

member x.Login(username, password,p12CertificateLocation:string, p12CertificatePassword:string) = 
    let AppKey = "APPKEY"
    let  url = "https://identitysso.betfair.com/api/certlogin"
    let postData =  "username=" + username + "&password=" + password
    let x509certificate = new X509Certificate2(p12CertificateLocation, p12CertificatePassword)

    let req = HttpWebRequest.Create(url) :?> HttpWebRequest 
    req.ClientCertificates.Add(x509certificate)|>ignore
    req.UseDefaultCredentials <- true
    req.Method <- "POST"
    req.ContentType <- "application/x-www-form-urlencoded"
    req.Headers.Add("X-Application",AppKey)
    req.Accept <-"*/*" 

    use stream = req.GetRequestStream()
    use writer =new StreamWriter(stream,Encoding.Default)                      
    writer.Write(postData)

    // fails on this line:
    use stream = (req.GetResponse()  :?> HttpWebResponse ).GetResponseStream()
    // with System.Net.WebException: 'The remote server returned an error: (400) Bad Request.'
    use reader = new StreamReader(stream,Encoding.Default)
member x.Login(用户名、密码、p12CertificateLocation:string、p12CertificatePassword:string)=
让AppKey=“AppKey”
让url=”https://identitysso.betfair.com/api/certlogin"
让postData=“username=“+username+”&password=“+password
设x509certificate=新的X509Certificate2(p12CertificateLocation,p12CertificatePassword)
让req=HttpWebRequest.Create(url):?>HttpWebRequest
请求客户端证书。添加(x509certificate)|>忽略
此C代码中的req.UseDefaultCredentials:

使用(streamstream1=request.GetRequestStream())
使用(StreamWriter=newstreamwriter(stream1,Encoding.Default))
writer.Write(postData);
使用(stream2=((HttpWebResponse)request.GetResponse()).GetResponseStream())
使用(StreamReader=newstreamreader(stream2,Encoding.Default))
writer
stream1
会在
writer.Write
调用完成后立即刷新并关闭,然后再调用
request.GetResponse()
(这一事实由于代码的格式非常有趣而有些模糊。)

在此F#代码中:

writer
stream1
在调用
req.GetResponse()
时保持活动状态并保持未刷新和未关闭状态;您需要将它们放在一个人工作用域中,以获得与C#相同的行为:

在此C#代码中:

使用(streamstream1=request.GetRequestStream())
使用(StreamWriter=newstreamwriter(stream1,Encoding.Default))
writer.Write(postData);
使用(stream2=((HttpWebResponse)request.GetResponse()).GetResponseStream())
使用(StreamReader=newstreamreader(stream2,Encoding.Default))
writer
stream1
会在
writer.Write
调用完成后立即刷新并关闭,然后再调用
request.GetResponse()
(这一事实由于代码的格式非常有趣而有些模糊。)

在此F#代码中:

writer
stream1
在调用
req.GetResponse()
时保持活动状态并保持未刷新和未关闭状态;您需要将它们放在一个人工作用域中,以获得与C#相同的行为:

这不是进行HTTP POST调用的“C#方式”。在所有受支持的.NET版本(ie 4.5.2及更高版本)中,典型的方式是使用HttpClient。即使使用HttpWebRequest,也有太多冗余或矛盾的调用,例如使用默认凭据(即Windows身份验证)

C#方法是:

var-client=新的HttpClient(“https://identitysso.betfair.com/api");
var值=新字典
{
{“用户名”,用户名},
{“密码”,密码}
};
var内容=新的FormUrlEncodedContent(值);
content.Headers.Add(“X-Application”,apiKey);
var response=wait client.PostAsync(“certlogin”,content);
var responseString=await response.Content.ReadAsStringAsync();
要使用客户端证书,必须使用自定义HTTP处理程序创建客户端实例:

var handler=new WebRequestHandler();
var x509certificate=新的X509Certificate2(certPath,certPassword);
handler.ClientCertificates.Add(证书);
var client=新的HttpClient(处理程序)
{
BaseAddress=新Uri(“https://identitysso.betfair.com/api")
}
用F#编写相同的代码很简单:

let login username password (certPath:string) (certPassword:string) (apiKey:string) = 
    let handler = new WebRequestHandler()
    let certificate = new X509Certificate2(certPath, certPassword)
    handler.ClientCertificates.Add certificate |> ignore
    let client = new HttpClient(handler,BaseAddress = Uri("https://identitysso.betfair.com"))

    async {    
        let values = dict["username", username ; "password", password ] 
        let content = new FormUrlEncodedContent(values)
        content.Headers.Add( "X-Application" ,apiKey)    

        let! response = client.PostAsync("api/certlogin",content) |> Async.AwaitTask
        response.EnsureSuccessStatusCode() |> ignore
        let! responseString = response.Content.ReadAsStringAsync() |> Async.AwaitTask
        return responseString
    }
客户端、处理程序是线程安全的,可以重复使用,以便存储在字段中。重复使用同一个客户端意味着操作系统不必每次都创建新的TCP/IP连接,从而提高性能。最好单独创建客户端:

let buildClient (certPath:string) (certPassword:string) =
    let handler = new WebRequestHandler()
    let certificate = new X509Certificate2(certPath, certPassword)
    handler.ClientCertificates.Add certificate |> ignore
    new HttpClient(handler,BaseAddress = Uri("https://identitysso.betfair.com"))


let login (client:HttpClient) username password  (apiKey:string) = 
    async {    
        let values = dict["username", username ; "password", password ] 
        let content = new FormUrlEncodedContent(values)
        content.Headers.Add( "X-Application" ,apiKey)    

        let! response = client.PostAsync("api/certlogin",content) |> Async.AwaitTask
        response.EnsureSuccessStatusCode() |> ignore
        let! responseString = response.Content.ReadAsStringAsync() |> Async.AwaitTask
        //Do whatever is needed here 
        return responseString
    }
这不是进行HTTP POST调用的“C#方式”。在所有受支持的.NET版本(ie 4.5.2及更高版本)中,典型的方式是使用HttpClient。即使使用HttpWebRequest,也有太多冗余或矛盾的调用,例如使用默认凭据(即Windows身份验证)

C#方法是:

var-client=新的HttpClient(“https://identitysso.betfair.com/api");
var值=新字典
{
{“用户名”,用户名},
{“密码”,密码}
};
var内容=新的FormUrlEncodedContent(值);
content.Headers.Add(“X-Application”,apiKey);
var response=wait client.PostAsync(“certlogin”,content);
风险反应
let login username password (certPath:string) (certPassword:string) (apiKey:string) = 
    let handler = new WebRequestHandler()
    let certificate = new X509Certificate2(certPath, certPassword)
    handler.ClientCertificates.Add certificate |> ignore
    let client = new HttpClient(handler,BaseAddress = Uri("https://identitysso.betfair.com"))

    async {    
        let values = dict["username", username ; "password", password ] 
        let content = new FormUrlEncodedContent(values)
        content.Headers.Add( "X-Application" ,apiKey)    

        let! response = client.PostAsync("api/certlogin",content) |> Async.AwaitTask
        response.EnsureSuccessStatusCode() |> ignore
        let! responseString = response.Content.ReadAsStringAsync() |> Async.AwaitTask
        return responseString
    }
let buildClient (certPath:string) (certPassword:string) =
    let handler = new WebRequestHandler()
    let certificate = new X509Certificate2(certPath, certPassword)
    handler.ClientCertificates.Add certificate |> ignore
    new HttpClient(handler,BaseAddress = Uri("https://identitysso.betfair.com"))


let login (client:HttpClient) username password  (apiKey:string) = 
    async {    
        let values = dict["username", username ; "password", password ] 
        let content = new FormUrlEncodedContent(values)
        content.Headers.Add( "X-Application" ,apiKey)    

        let! response = client.PostAsync("api/certlogin",content) |> Async.AwaitTask
        response.EnsureSuccessStatusCode() |> ignore
        let! responseString = response.Content.ReadAsStringAsync() |> Async.AwaitTask
        //Do whatever is needed here 
        return responseString
    }