Como mencioné, porque Silverlight HttpWebRequest.Create hangs inside async block, acabo de crear un conjunto de funciones de devolución de llamada para implementar el mismo bloque asincrónico.Cómo crear una HttpWebRequest asíncrona en Silverlight (F #)
El proceso de inicio de sesión requiere dos pasos:
1) Obtener solicitud a una página que devuelve una cookie 2) el envío de formularios a una segunda página que pasa esa galleta w/ella y realiza la autenticación
El siguiente es el src. Cualquier sugerencia y discusión son bienvenidas y apreciadas sin importar la Asynchronous HttpWebRequest o el estilo de código 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
()
Para crear una instancia de registro, he intentado su método. Sin embargo, no funcionó solo en mi código, porque hay otro tipo de registro (genérico) que tiene el mismo campo que este. "let authentication: AuthenticationRecord = {...}" puede funcionar y también aplicarse al tipo de registro definido en otro módulo. La línea fprintf es muy ordenada. muy agradable. Muchas gracias ~! –