Async POST schlägt in WP7 und F # fehl


86

Wenn ich let! read = from.AsyncRead bufin F # mache , blockiert es und kehrt erst zurück, wenn der TCP-Socket tot ist. Warum? Und wie behebe ich das?

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

Es wird von diesem Code aufgerufen:

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

und über HTTP mit diesem Code vom Windows Phone 7.1-Emulator angefordert:

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

Vergeblich. Der ResponseReadyRückruf wird nie erreicht.

Inzwischen funktioniert dieser Code hervorragend:

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

Ich konnte Fiddler2 nicht mit WP7 zum Laufen bringen.

EDIT: Willkommen in einem Yak. Ich bin selbst auf grünere Weiden gezogen;)


9
Wenn from.AsyncReadblockiert, bedeutet dies, dass der Remote-Server keine Bytes sendet.
Qehgt

Ich bin von dem Problem weggekommen, dass der Stream nicht richtig geschlossen wird, aber ich erhalte immer noch nur Dateien mit einer Größe von 40 Bytes auf der Empfangsseite und in WP viele Operationen, die den Auslöser NotSupportedException blockieren, anstatt nicht verfügbar zu sein Das Debuggen ist also sehr schmerzhaft. Ich werde eine vollständige Lösung veröffentlichen, wenn ich dazu komme.
Henrik

Ich habe diese Frage nicht vergessen. Nur viel zu tun, wird in Kürze behoben.
Henrik

5
Dies kann für Sie nützlich sein, wenn Sie versuchen, Fiddler mit mobilen Geräten zum Laufen zu bringen
Alpha

2
Ist dies nicht das erwartete Verhalten, wenn Sie eine unendliche Anzahl von Bytes von einem TCP-Socket anfordern?
Jyoung

Antworten:


1

Sie sollten die Bytes vor dem Senden und Verwenden der BufferStream INput-Ausgabe in die eingeben

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.