2012-05-16 93 views
84

當我在F#中使用let! read = from.AsyncRead buf時,它會阻塞並且不會返回,直到TCP套接字終止。爲什麼?我該如何解決它?異步POST在WP7和F#上失敗

其代碼:

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

它正從該代碼調用:

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

,並要求通過HTTP與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()); 
    } 
} 

未成功。 ResponseReady回調永遠不會到達。

同時,該代碼做工精良:

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 

我不能得到Fiddler2與WP7的工作。

編輯:歡迎來到犛牛。我移動到綠色的牧場我自己;)

+9

如果'from.AsyncRead'塊這意味着遠程服務器不發送任何字節之前。 – qehgt

+0

我已經擺脫了流無法正常關閉的問題,但我仍然只能在接收端和WP上獲取大小超過40個字節的文件,而很多阻止的操作會拋出NotSupportedException,而不是不存在可用,所以調試真的很痛苦。當我到達它時,我會發佈一個完整的解決方案。 – Henrik

+0

我沒有忘記這個問題;現在做很多事情,很快就會解決。 – Henrik

回答

1

你應該把字節到發送和使用BufferStream輸入輸出