Async POST falla en WP7 y F #

87

Cuando lo hago let! read = from.AsyncRead bufen F #, se bloquea y no regresa hasta que el socket TCP está muerto. ¿Por qué? ¿Y cómo lo soluciono?

Su código:

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 ()

Se llama desde este código:

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

y solicitado a través de HTTP con este código del emulador de Windows Phone 7.1:

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());
    }
}

Sin éxito. La ResponseReadydevolución de llamada nunca se alcanza.

Mientras tanto, este código funciona excelente:

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

No pude hacer que Fiddler2 funcionara con WP7.

EDITAR: Bienvenido a un yak. Yo mismo me mudé a pastos más verdes;)

Henrik
fuente
9
Si se from.AsyncReadbloquea, eso significa que el servidor remoto no envía ningún byte.
qehgt
Me he salvado del problema de que la transmisión no se cierra correctamente, pero todavía obtengo archivos de 40 bytes de tamaño en el lado receptor y en WP muchas operaciones que están bloqueando lanzan NotSupportedException en lugar de no estar disponibles , por lo que es muy doloroso depurarlo. Voy a publicar una solución completa cuando llegue a ella.
Henrik
No he olvidado esta pregunta; solo hay mucho que hacer en este momento, publicaremos la solución en breve.
Henrik
5
Esto puede serle útil si está tratando de hacer que el violinista funcione con dispositivos móviles: diaryofaninja.com/blog/2010/11/09/…
Alpha
2
¿No es este el comportamiento esperado cuando solicita una cantidad infinita de bytes desde un socket TCP?
jyoung

Respuestas:

1

Debe poner los bytes en el antes de enviar y usar la salida de entrada de BufferStream

Raju yourPepe
fuente