开发者

Get Asynchronous HttpResponse through Silverlight (F#)

I am a newbie with F# and SL and playing with getting asynchronous HttpResponse through Silverlight. The following is the F# code pieces, which is tested on VS2010 and Window7 and works well, but the improvement is necessary. Any advices and discussion, especially the callback part, are welcome and great thanks.

module JSONExample
open System
open System.IO 
open System.Net 
open System.Text 
open System.Web 
open System.Security.Authentication 
open System.Runtime.Serialization 


[<DataContract>] 
type Result<'TResult> = { 
    [<field: DataMember(Name="code") >] 
    Code:string 
开发者_运维知识库    [<field: DataMember(Name="result") >] 
    Result:'TResult array
    [<field: DataMember(Name="message") >] 
    Message:string 
    } 

// The elements in the list
[<DataContract>] 
type ChemicalElement = { 
    [<field: DataMember(Name="name") >] 
    Name:string 
    [<field: DataMember(Name="boiling_point") >] 
    BoilingPoint:string 
    [<field: DataMember(Name="atomic_mass") >] 
    AtomicMass:string 
} 



//http://blogs.msdn.com/b/dsyme/archive/2007/10/11/introducing-f-asynchronous-workflows.aspx
//http://lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!194.entry
type System.Net.HttpWebRequest with
    member x.GetResponseAsync() =
        Async.FromBeginEnd(x.BeginGetResponse, x.EndGetResponse)


type RequestState () = 
    let mutable request : WebRequest = null
    let mutable response : WebResponse = null
    let mutable responseStream : Stream = null
    member this.Request with get() = request and set v = request <- v
    member this.Response with get() = response and set v = response <- v
    member this.ResponseStream with get() = responseStream and set v = responseStream <- v

let allDone = new System.Threading.ManualResetEvent(false)


let getHttpWebRequest (query:string) = 
    let query = query.Replace("'","\"") 
    let queryUrl = sprintf "http://api.freebase.com/api/service/mqlread?query=%s" "{\"query\":"+query+"}" 

    let request : HttpWebRequest = downcast WebRequest.Create(queryUrl) 
    request.Method <- "GET" 
    request.ContentType <- "application/x-www-form-urlencoded" 
    request


let GetAsynResp (request : HttpWebRequest) (callback: AsyncCallback) = 
    let myRequestState = new RequestState()
    myRequestState.Request <- request
    let asyncResult = request.BeginGetResponse(callback, myRequestState)
    ()


// easy way to get it to run syncrnously w/ the asynch methods
let GetSynResp (request : HttpWebRequest) : HttpWebResponse  =      
    let response = request.GetResponseAsync() |> Async.RunSynchronously  
    downcast response

let RespCallback (finish: Stream -> _) (asynchronousResult : IAsyncResult) =
        try
            let myRequestState : RequestState = downcast asynchronousResult.AsyncState 
            let myWebRequest1 : WebRequest = myRequestState.Request
            myRequestState.Response <- myWebRequest1.EndGetResponse(asynchronousResult)
            let responseStream = myRequestState.Response.GetResponseStream()
            myRequestState.ResponseStream <- responseStream
            finish responseStream
            myRequestState.Response.Close() 
            ()
        with 
        | :? WebException as e
            -> printfn "WebException raised!"
               printfn "\n%s" e.Message
               printfn "\n%s" (e.Status.ToString())
               ()
        | _ as e
            -> printfn "Exception raised!"
               printfn "Source : %s" e.Source
               printfn "Message : %s" e.Message
               ()

let printResults (stream: Stream)= 
    let result = 
        try 
            use reader = new StreamReader(stream) 
            reader.ReadToEnd(); 
        finally 
            ()

    let data = Encoding.Unicode.GetBytes(result); 
    let stream = new MemoryStream() 
    stream.Write(data, 0, data.Length); 
    stream.Position <- 0L 

    let JsonSerializer = Json.DataContractJsonSerializer(typeof<Result<ChemicalElement>>) 
    let result = JsonSerializer.ReadObject(stream) :?> Result<ChemicalElement> 

    if result.Code<>"/api/status/ok" then 
        raise (InvalidOperationException(result.Message)) 
    else 
        result.Result |> Array.iter(fun element->printfn "%A" element) 

let test =
    // Call Query (w/ generics telling it you wand an array of ChemicalElement back, the query string is wackyJSON too –I didn’t build it don’t ask me!
    let request = getHttpWebRequest "[{'type':'/chemistry/chemical_element','name':null,'boiling_point':null,'atomic_mass':null}]"
    //let response = GetSynResp request 
    let response = GetAsynResp request (AsyncCallback (RespCallback printResults))
    () 

ignore(test)
System.Console.ReadLine() |> ignore


The whole point of async is that you don't have to deal with state and IAsyncResult and Callbacks and whatnot. Below is a somewhat cleaned-up version of your code...

open System 
open System.IO  
open System.Net  
open System.Text  
open System.Web  
open System.Security.Authentication  
open System.Runtime.Serialization  

[<DataContract>]  
type Result<'TResult> = {  
    [<field: DataMember(Name="code") >]  
    Code:string  
    [<field: DataMember(Name="result") >]  
    Result:'TResult array 
    [<field: DataMember(Name="message") >]  
    Message:string  
    }  

// The elements in the list 
[<DataContract>]  
type ChemicalElement = {  
    [<field: DataMember(Name="name") >]  
    Name:string  
    [<field: DataMember(Name="boiling_point") >]  
    BoilingPoint:string  
    [<field: DataMember(Name="atomic_mass") >]  
    AtomicMass:string  
}  

//http://blogs.msdn.com/b/dsyme/archive/2007/10/11/introducing-f-asynchronous-workflows.aspx 
//http://lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!194.entry 
type System.Net.HttpWebRequest with 
    member x.GetResponseAsync() = 
        Async.FromBeginEnd(x.BeginGetResponse, x.EndGetResponse) 

let getHttpWebRequest (query:string) =  
    let query = query.Replace("'","\"")  
    let queryUrl = sprintf "http://api.freebase.com/api/service/mqlread?query=%s" "{\"query\":"+query+"}"  

    let request : HttpWebRequest = downcast WebRequest.Create(queryUrl)  
    request.Method <- "GET"  
    request.ContentType <- "application/x-www-form-urlencoded"  
    request 

let printResults (stream: Stream)=  
    let result =  
        try  
            use reader = new StreamReader(stream)  
            reader.ReadToEnd();  
        finally  
            () 

    let data = Encoding.Unicode.GetBytes(result);  
    let stream = new MemoryStream()  
    stream.Write(data, 0, data.Length);  
    stream.Position <- 0L  

    let JsonSerializer = Json.DataContractJsonSerializer(typeof<Result<ChemicalElement>>)  
    let result = JsonSerializer.ReadObject(stream) :?> Result<ChemicalElement>  

    if result.Code<>"/api/status/ok" then  
        raise (InvalidOperationException(result.Message))  
    else  
        result.Result |> Array.iter(fun element->printfn "%A" element)  

let test = async {
    // Call Query (w/ generics telling it you wand an array of ChemicalElement back, the query string is wackyJSON too –I didn’t build it don’t ask me! 
    let request = getHttpWebRequest "[{'type':'/chemistry/chemical_element','name':null,'boiling_point':null,'atomic_mass':null}]" 
    try 
        use! response = request.AsyncGetResponse()
        use responseStream = response.GetResponseStream() 
        printResults responseStream 
    with  
    | :? WebException as e 
        ->  printfn "WebException raised!" 
            printfn "\n%s" e.Message 
            printfn "\n%s" (e.Status.ToString()) 
    | _ as e 
        ->  printfn "Exception raised!" 
            printfn "Source : %s" e.Source 
            printfn "Message : %s" e.Message 
}

test |> Async.RunSynchronously 
System.Console.ReadLine() |> ignore 
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜