gpt4 book ai didi

silverlight - 如何在 Silverlight( F#) 中创建异步 HttpWebRequest

转载 作者:行者123 更新时间:2023-12-04 02:29:36 25 4
gpt4 key购买 nike

正如我提到的,因为 Silverlight HttpWebRequest.Create hangs inside async block ,我刚刚创建了一组回调函数来实现相同的异步块。

登录过程需要两个步骤:

1) 获取对返回 cookie 的页面的请求
2)将表单发布到第二个页面,该页面通过该 cookie 传递并执行身份验证

以下是源代码。无论是关于异步 HttpWebRequest 还是关于 F# 代码样式,任何建议和讨论都受到欢迎和赞赏。

module File1

open System
open System.IO
open System.Net
open System.Text
open System.Security
open System.Runtime.Serialization
open System.Collections.Generic
open JsonData
open System.Net.Browser
open System.Threading


module rpc =
let mutable BASE_DNS = ""

let mutable requestId : int = 0
let getId() =
requestId <- requestId + 1
requestId.ToString()

module internal Helper =
///<Summary>
///Transfer data from Security.loginToRpc to Helper.FetchCookieCallback
///</Summary>
type LoginRequestRecord = {
Request : HttpWebRequest;
UserName : string;
Password : string;
AuthenticationUrl : string;
CallbackUI : (bool -> unit)
}

///<Summary>
///Transfer data from Helper.FetchCookieCallback to Helper.requestAuthenticationCallback
///</Summary>
type AuthenticationRecord = {
Request : HttpWebRequest;
UserName : string;
Password : string;
CallbackUI : (bool -> unit)
}

///<Summary>
///Transfer data from Helper.requestAuthenticationCallback to Helper.responseAuthenticationCallback
///</Summary>
type ResponseAuthenticationRecord = {
Request : HttpWebRequest;
CallbackUI : (bool -> unit)
}

///<Summary>
///The cookieContainer for all the requests in the session
///</Summary>
let mutable cookieJar = new CookieContainer()

///<summary>
///Function: Create HttpRequest
///Param: string
///Return: HttpWebRequest
///</summary>
let internal createHttpRequest (queryUrl : string) =
let uri = new Uri(queryUrl)
let request : HttpWebRequest =
downcast WebRequestCreator.ClientHttp.Create(
new Uri(queryUrl, UriKind.Absolute))
request

///<summary>
///Function: set request whose method is "GET".
///Attention: no contentType for "GET" request~!!!!!!!!!!!!!!!!
///Param: HttpWebRequest
///Return: unit
///</summary>
let internal requestGetSet (request : HttpWebRequest) =
request.Method <- "GET"

///<summary>
///Function: set request whose method is "POST" and its contentType
///Param: HttpWebRequest and contentType string
///Return: unit
///</summary>
let internal requestPostSet (request : HttpWebRequest) contentType =
request.Method <- "POST"
request.ContentType <- contentType

///<summary>
///Function: Callback function inluding EndGetResponse method of request
///Param: IAsyncResult includes the information of HttpWebRequest
///Return: unit
///</summary>
let internal responseAuthenticationCallback (ar : IAsyncResult) =
let responseAuthentication : ResponseAuthenticationRecord
= downcast ar.AsyncState
try
let response = responseAuthentication.Request.EndGetResponse(ar)
//check whether the authentication is successful,
//which may be changed later into other methods
match response.ContentLength with
| -1L -> responseAuthentication.CallbackUI true
| _ -> responseAuthentication.CallbackUI false
()
with
| Ex -> responseAuthentication.CallbackUI false

///<summary>
///Function: Callback function for user to log into the website
///Param: IAsyncResult includes the information of
///HttpWebRequest and user's identity
///Return: unit
///</summary>
let internal requestAuthenticationCallback (ar : IAsyncResult) =
let authentication : AuthenticationRecord = downcast ar.AsyncState
try
let requestStream = authentication.Request.EndGetRequestStream(ar)
let streamWriter = new StreamWriter(requestStream)
streamWriter.Write(
String.Format(
"j_username={0}&j_password={1}&login={2}",
authentication.UserName,
authentication.Password,
"Login"))
streamWriter.Close()
let responseAuthentication = {
ResponseAuthenticationRecord.Request = authentication.Request
ResponseAuthenticationRecord.CallbackUI = authentication.CallbackUI
}
authentication.Request.BeginGetResponse(
new AsyncCallback(responseAuthenticationCallback),
responseAuthentication)
|> ignore
with
| Ex -> authentication.CallbackUI false
()

///<summary>
///This is a magic number to check
///whether the first request have got the cookie from the server-side,
///which should be changed later
///</summary>
let countHeadersAfterGetCookie = 8

///<summary>
///Function: Callback function to get the cookie and
///Param: IAsyncResult includes the information of
///login request, username, password and callbackUI
///Return:
///</summary>
let internal FetchCookieCallback (ar : IAsyncResult) =
let loginRequest : LoginRequestRecord = downcast ar.AsyncState
try
let response = loginRequest.Request.EndGetResponse(ar)
let request : HttpWebRequest
= createHttpRequest loginRequest.AuthenticationUrl
requestPostSet request "application/x-www-form-urlencoded"
request.CookieContainer <- cookieJar

//if the cookie is got, call the callback function; or else, return to UI
match response.Headers.Count with
| countHeadersAfterGetCookie ->
let authentication = {
AuthenticationRecord.Request = request;
AuthenticationRecord.UserName = loginRequest.UserName;
AuthenticationRecord.Password = loginRequest.Password;
AuthenticationRecord.CallbackUI = loginRequest.CallbackUI
}
request.BeginGetRequestStream(
new AsyncCallback(requestAuthenticationCallback),
authentication)
|> ignore
()
| _ ->
loginRequest.CallbackUI false
()
with
| Ex -> loginRequest.CallbackUI false

module Security =
///<summary>
///Function: Use the async workflow around 2 we calls:
/// 1. get the cookie; 2. log into the website
///Param: UserName and password
///Return: unit
///</summary>
let loginToRpc (userName : string)
(password : string)
(callbackUI : (bool-> unit)) =
let sessionIdUrl = BASE_DNS
let authenticationUrl = BASE_DNS + "..................."
let request : HttpWebRequest = Helper.createHttpRequest sessionIdUrl
Helper.requestGetSet(request)
request.CookieContainer <- Helper.cookieJar
let loginRequest = {
Helper.LoginRequestRecord.Request = request
Helper.LoginRequestRecord.UserName = userName
Helper.LoginRequestRecord.Password = password
Helper.LoginRequestRecord.AuthenticationUrl = authenticationUrl
Helper.LoginRequestRecord.CallbackUI = callbackUI
}
request.BeginGetResponse(new
AsyncCallback(Helper.FetchCookieCallback),
loginRequest)
|> ignore
()

最佳答案

通常,在创建记录实例时,无需像您所做的那样完全限定每个属性。

let authentication = {
AuthenticationRecord.Request = request;
AuthenticationRecord.UserName = loginRequest.UserName;
AuthenticationRecord.Password = loginRequest.Password;
AuthenticationRecord.CallbackUI = loginRequest.CallbackUI
}

只要您使用的属性的名称和类型只匹配一种记录类型,F# 通常就足够聪明,可以弄清楚您的意思。
let authentication = {
Request = request;
UserName = loginRequest.UserName;
Password = loginRequest.Password;
CallbackUI = loginRequest.CallbackUI
}

另外,我可能倾向于使用 sprintfString.Format这里:
String.Format(
"j_username={0}&j_password={1}&login={2}",
authentication.UserName,
authentication.Password,
"Login"))

sprintf "j_username=%s&j_password=%s&login=%s"
authentication.UserName authentication.Password "Login"

但是由于结果字符串被传递给 StreamWriter ,继承自 TextWriter另一种选择是使用 fprintf 直接写入 TextWriter .
fprintf streamWriter "j_username=%s&j_password=%s&login=%s" 
authentication.UserName authentication.Password "Login"

关于silverlight - 如何在 Silverlight( F#) 中创建异步 HttpWebRequest,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3085728/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com