Async POST gagal di WP7 dan F #

87

Ketika saya lakukan let! read = from.AsyncRead bufdi F #, itu memblokir dan tidak kembali sampai soket TCP mati. Mengapa? Dan bagaimana cara memperbaikinya?

Kodenya:

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

Itu dipanggil dari kode ini:

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

dan diminta melalui HTTP dengan kode ini dari emulator 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());
    }
}

Tidak berhasil. The ResponseReadycallback tidak pernah tercapai.

Sementara itu, kode ini berfungsi dengan sangat baik:

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

Saya tidak bisa membuat Fiddler2 bekerja dengan WP7.

EDIT: Selamat datang di yak. Saya sendiri telah pindah ke padang rumput yang lebih hijau;)

Henrik
sumber
9
Jika from.AsyncReadblok itu berarti server jarak jauh tidak mengirim byte apa pun.
qehgt
Saya telah lolos dari masalah bahwa aliran tidak menutup dengan benar, tetapi saya masih hanya mendapatkan file berukuran besar 40 byte di sisi penerima dan di WP banyak operasi yang memblokir lemparan NotSupportedException alih-alih tidak tersedia , jadi sangat menyakitkan untuk men-debug. Saya akan memposting solusi lengkap ketika saya sampai di sana.
Henrik
Saya belum melupakan pertanyaan ini; hanya banyak yang harus dilakukan sekarang, akan segera diperbaiki.
Henrik
5
Ini mungkin berguna bagi Anda jika Anda mencoba membuat fiddler berfungsi dengan perangkat seluler: diaryofaninja.com/blog/2010/11/09/…
Alfa
2
Bukankah ini perilaku yang diharapkan ketika Anda meminta jumlah byte yang tak terbatas dari soket TCP?
jyoung

Jawaban:

1

Anda harus memasukkan byte ke dalam sebelum mengirim dan menggunakan keluaran BufferStream INput

Raju yourPepe
sumber