87

When I do let! read = from.AsyncRead buf in F#, it blocks and doesn't return until the TCP socket is dead. Why? And how do I fix it?

Its code:

module StreamUtil open System.IO /// copy from 'from' stream to 'toStream' let (|>>) (from : Stream) (toStream : Stream) = let buf = Array.zeroCreate<byte> 1024 let rec doBlock () = async { let! read = from.AsyncRead buf if read <= 0 then toStream.Flush() return () else do! toStream.AsyncWrite(buf, 0, read) return! doBlock () } doBlock () 

It's being called from this code:

use fs = new FileStream(targPath, FileMode.CreateNew, FileAccess.ReadWrite) do! req.InputStream |>> fs 

and requested over HTTP with this code from Windows Phone 7.1 emulator:

public void Send() { var b = new UriBuilder(_imageService.BaseUrl) {Path = "/images"}; var req = WebRequest.CreateHttp(b.Uri); req.ContentType = "image/jpeg"; req.Method = "POST"; var imgLen = SelectedImage.ImageStream.Length; req.Headers[HttpRequestHeader.ContentLength] = imgLen.ToString(CultureInfo.InvariantCulture); req.Accept = "application/json"; req.BeginGetRequestStream(RequestReady, new ReqState(req, imgLen)); } void RequestReady(IAsyncResult ar) { var state = (ReqState)ar.AsyncState; var req = state.Request; var reqStream = req.EndGetRequestStream(ar); SmartDispatcher.BeginInvoke(() => { using (var sw = new StreamWriter(reqStream)) using (var br = new BinaryReader(SelectedVoucher.ImageStream)) { var readBytes = br.ReadBytes(state.ImgLen); // tried both 2 sw.Write(readBytes); //sw.Write(Convert.ToBase64String(readBytes)); sw.Flush(); sw.Close(); } req.BeginGetResponse(ResponseReady, req); }); } // WHY IS IT YOU ARE NOT CALLED??? void ResponseReady(IAsyncResult ar) { try { var request = (HttpWebRequest)ar.AsyncState; var response = request.EndGetResponse(ar); SmartDispatcher.BeginInvoke(() => { var rdr = new StreamReader(response.GetResponseStream()); var msg = rdr.ReadToEnd(); var imageLocation = response.Headers["Location"]; Debug.WriteLine(msg); Debug.WriteLine(imageLocation); }); } catch (WebException ex) { Debug.WriteLine(ex.ToString()); } catch (Exception ex) { Debug.WriteLine(ex.ToString()); } } 

Unsuccessfully. The ResponseReady callback is never reached.

Meanwhile, this code works excellent:

open System open System.Net.Http // WebAPI nuget let sync aw = Async.RunSynchronously aw let postC<'a> (c : HttpClient) (r : Uri) (cont : HttpContent) = let response = sync <| Async.AwaitTask( c.PostAsync(r, cont) ) let struc:'a = sync <| deserialize<'a> response response, struc let withContent<'a> (fVerb : (HttpClient -> Uri -> HttpContent -> _ * 'a))= let c = new HttpClient() fVerb c [<Test>] let ``POST /images 201 + Location header`` () = let post = withContent<MyImage> postC let bytes = IO.File.ReadAllBytes("sample.jpg") let hash = SHA1.Create().ComputeHash(bytes) |> Convert.ToBase64String let pic = new ByteArrayContent(bytes) pic.Headers.Add("Content-Type", "image/jpeg") pic.Headers.Add("X-SHA1-Hash", hash) let resp, ri = (resource "/images", pic) ||> post resp.StatusCode =? Code.Created ri.sha1 =? hash mustHaveHeaders resp 

I couldn't get Fiddler2 working with WP7.

EDIT: Welcome to a yak. I've moved onto greener pastures myself ;)

10
  • 9
    If from.AsyncRead blocks that means that remote server does not send any bytes. Commented May 16, 2012 at 15:19
  • I've gotten away from the problem that the stream doesn't close properly, but I'm still only getting files sized 40 bytes large on the receiving side and on WP a lot of operations that are blocking throw NotSupportedException instead of not being available, so it's really painful to debug. I'm going to post a complete solution when I arrive at it. Commented May 16, 2012 at 19:50
  • I haven't forgotten this question; just a lot to do right now, will post fix shortly. Commented Jun 25, 2012 at 14:36
  • 5
    This may be useful to you if you're trying to make fiddler work with mobile devices: diaryofaninja.com/blog/2010/11/09/… Commented Jul 6, 2012 at 21:32
  • 2
    Isn't this expected behaviour when you request an infinite amount of bytes from a TCP socket? Commented Sep 1, 2012 at 15:08

1 Answer 1

1

YOu should put the bytes into the before sending and using BufferStream INput output

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.