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