Async POST échoue sur WP7 et F #

87

Quand je le fais let! read = from.AsyncRead bufen F #, il bloque et ne revient pas tant que le socket TCP n'est pas mort. Pourquoi? Et comment résoudre ce problème?

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

Il est appelé à partir de ce code:

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

et demandé via HTTP avec ce code de l'émulateur 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());
    }
}

En vain. Le ResponseReadyrappel n'est jamais atteint.

Pendant ce temps, ce code fonctionne parfaitement:

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

Je n'ai pas pu faire fonctionner Fiddler2 avec WP7.

EDIT: Bienvenue chez un yack. J'ai moi-même déménagé sur des pâturages plus verts;)

Henrik
la source
9
Si from.AsyncReadbloque cela signifie que le serveur distant n'envoie aucun octet.
qehgt
Je me suis éloigné du problème que le flux ne se ferme pas correctement, mais je ne reçois toujours que des fichiers d'une taille de 40 octets du côté de la réception et sur WP, de nombreuses opérations qui bloquent lancent NotSupportedException au lieu de ne pas être disponibles , donc c'est vraiment pénible à déboguer. Je vais publier une solution complète lorsque j'y arriverai.
Henrik
Je n'ai pas oublié cette question; juste beaucoup à faire pour le moment, sera bientôt corrigé.
Henrik
5
Cela peut vous être utile si vous essayez de faire fonctionner un violoneux avec des appareils mobiles: diaryofaninja.com/blog/2010/11/09/…
Alpha
2
N'est-ce pas ce comportement attendu lorsque vous demandez une quantité infinie d'octets à partir d'un socket TCP?
jyoung

Réponses:

1

Vous devez placer les octets dans la sortie avant d'envoyer et d'utiliser BufferStream INput

Raju yourPepe
la source