After shamelessly pilfering a code snippet from Tomas Petricek’s Blog:
http://tomasp.net/blog/csharp-fsharp-async-intro.aspx
Specifically, this one (and making a few alterations to it):
let downloadPage(url:string) (postData:string) = async {
let request = HttpWebRequest.Create(url)
// Asynchronously get response and dispose it when we're done
use! response = request.AsyncGetResponse()
use stream = response.GetResponseStream()
let temp = new MemoryStream()
let buffer = Array.zeroCreate 4096
// Loop that downloads page into a buffer (could use 'while'
// but recursion is more typical for functional language)
let rec download() = async {
let! count = stream.AsyncRead(buffer, 0, buffer.Length)
do! temp.AsyncWrite(buffer, 0, count)
if count > 0 then return! download() }
// Start the download asynchronously and handle results
do! download()
temp.Seek(0L, SeekOrigin.Begin) |> ignore
let html = (new StreamReader(temp)).ReadToEnd()
return html };;
I tried to do the following with it, and got the error on the last line:
The type was expected to have type
Async<'a>but hasstring -> Asnyc<'a>instead
I googled the error but couldn’t find anything that revealed my particular issue.
let postData = "userid=" + userId + "&password=" + password + "&source=" + sourceId + "&version=" + version
let url = postUrlBase + "100/LogIn?" + postData
Async.RunSynchronously (downloadPage(url, postData));;
Also, how would I modify the code so that it downloads a non-ending byte stream (but with occasional pauses between each burst of bytes) asynchronously instead of a string? How would I integrate reading this byte stream as it comes through? I realize this is more than one question, but since they are are all closely related I figured one question would save some time.
Thanks in advance,
Bob
P.S. As I am still new to F# please feel free to make any alterations/suggestions to my code which shows how its done in a more functional style. I’m really trying to get out of my C# mindset, so I appreciate any pointers anyone may wish to share.
Edit: I accidentally pasted in the wrong snippet I was using. I did make an alteration to Tomas’ snippet and forgot about it.
When I attempt to run your code
downloadPage(url, postData)doesn’t work asdownloadPageexpects two seperate strings.downloadPage url postDatais what is expected.If you changed the
letbinding to tuple form, orlet downloadPage(url:string, postData:string)your call would have worked as well.To explain why you got the error you got is more complicated. Curried form creates a function that returns a function or
string -> string -> Async<string>in your case. The compiler therefore saw you passing a single parameter (tuples are single items after all) and saw that the result would have to be astring -> Async<string>which is not compatible withAsync<string>. Another error it could have found (and did in my case) is thatstring * stringis not compatible withstring. The exact error beingExpected string but found 'a * 'b.