2012-11-23 10 views
6

私はWPFデスクトップアプリケーションと通信するために使用されるASP.Net Web APIを自分のWebサイトに設定しています。私は、クライアントアプリケーションからバイナリファイルを受け取るためのAPIのアクション設定を持っています。しかし、いくつかの(一見ランダムな)ケースでは、リクエストからすべてのバイトを取得すると、すべてのバイトが読み込まれるわけではありません。うまくいけば、あなたは私にすべての時間に作用する方法でこれを行う方法のアイデアを与えることができます。ASP.Net Web APIがStreamContentからすべてのバイトを読み取らない

クライアント側:

public static SubmitTurnResult SubmitTurn(int turnId, Stream fileStream) 
{ 
    HttpClient client = CreateHttpClient(); 

    HttpContent content = new StreamContent(fileStream); 
    content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); 
    content.Headers.ContentDisposition.FileName = "new-turn.Civ5Save"; 
    content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); 
    content.Headers.ContentLength = fileStream.Length; 

    HttpResponseMessage response = client.PostAsync(
     string.Format("SubmitTurn?authKey={0}&turnId={1}", 
         LocalSettings.Instance.AuthenticationKey, 
         turnId 
         ), 
     content 
    ).Result; 

    response.EnsureSuccessStatusCode(); 

    return response.Content.ReadAsAsync<SubmitTurnResult>().Result; 
} 

SubmitTurnResultは、サーバー上の結果を定義する列挙型、turnIdは、エンティティのIDは、このファイルはに添付されており、ここでは、コードですfileStreamは、ディスクのバイトを読み取る実際のFileStreamです。

サーバーサイド:

[HttpGet, HttpPost] 
public SubmitTurnResult SubmitTurn(string authKey, int turnId) 
{ 

    try 
    { 
     bool worked = false; 
     int gameId = 0; 

     using (GmrEntities gmrDb = new GmrEntities()) 
     { 
      var player = gmrDb.Users.FirstOrDefault(u => u.AuthKey == authKey); 
      if (player != null) 
      { 
       var turn = player.Turns.FirstOrDefault(t => t.TurnID == turnId); 
       if (turn != null) 
       { 
        byte[] saveFileBytes = null; 

        using (MemoryStream tempStream = new MemoryStream()) 
        { 
         var task = this.Request.Content.CopyToAsync(tempStream); 
         task.Wait(); 

         saveFileBytes = tempStream.ToArray(); 
         tempStream.Close(); 
        } 

        if (saveFileBytes.Length != this.Request.Content.Headers.ContentLength.Value) 
        { 
         throw new Exception(string.Format("Byte array length ({0}) not equal to HTTP content-length header ({1}). This is not good!", 
            saveFileBytes.Length, this.Request.Content.Headers.ContentLength.Value)); 
        } 

        worked = GameManager.SubmitTurn(turn, saveFileBytes, gmrDb); 

        if (worked) 
        { 
         gameId = turn.Game.GameID; 

         gmrDb.SaveChanges(); 
        } 
       } 
      } 
     } 


     return SubmitTurnResult.OK; 
    } 
    catch (Exception exc) 
    { 
     DebugLogger.WriteExceptionWithComments(exc, string.Format("Diplomacy: Sumbitting turn for turnId: {0}", turnId)); 

     return SubmitTurnResult.UnexpectedError; 
    } 
} 
+0

これは32ビットWindows Server 2003またはWindows XPでですか? StreamContentでは、Windows Server 2003 Web APIサービスからの応答をストリーミングするときも、この同じ動作が実行されています。 2008年には復習しません。また、これはFileStreamを使用して復旧するだけです。 FileStreamをMemoryStreamに変換すると、問題は回避されます(もちろんメモリを犠牲にして)。レスポンスストリームが早く終了すると、それは常に4096バイトの境界にあり、約3.5MBの上限に達していることがわかりました。 –

答えて

11

私の以前のコメントで述べたように、我々はStreamContentと、この同じ動作に走ったが、Windows Server 2003のウェブAPIサービスからの応答をストリーミングするとき。 2008年に再書き込みしません。 実際には、少量のRAM(712 MB)でVMを構成すると、Windows Server 2008でもreproが実行されますが、4 GBのRAMでは再書き込みできません。また、これはFileStreamを使用した場合にのみ表示されることがわかりました。 FileStreamをMemoryStreamに変換すると、問題は回避されます(もちろんメモリを犠牲にして)。レスポンスストリームが早く終了すると、それは常に4096バイトの境界にあり、3.5MB前後の上限に達していることがわかりました。

はここにあなたのコード例に合わせて、私のために物事を固定し、回避策です:

public static SubmitTurnResult SubmitTurn(int turnId, Stream fileStream) 
{ 
    HttpClient client = CreateHttpClient(); 

    var memoryStream = new MemoryStream((int)fileStream.Length); 
    fileStream.CopyTo(memoryStream); 
    fileStream.Close(); 
    memoryStream.Seek(0, SeekOrigin.Begin); 
    HttpContent content = new StreamContent(memoryStream); 

必要に応じてストリームがFileStreamをされた場合にのみ、あなたは条件付きでMemoryStreamをコピーを行うことができます。

+0

あなたの提案をありがとう、残念ながら、それは私の問題を解決しませんでした。コードのクライアント部分は、WinXPからWin8.1までの何百ものマシン上で動作しており、FileStreamの代わりにMemoryStreamを使用するように変更しました。そのサーバー部分はWinServer 2012R2で実行されています。私は今も問題を経験しており、サーバーがコンテンツストリームから読み取ったバイト数がクライアントによって送信されたバイト数と一致しない場合は\ –

+0

です。これは本当に残念ですが、私の "解決策"それはこれまで私のために働いているようだ。あなたのケースでできることは、HTTPレスポンスが成功しなかった場合にクライアント側のリトライロジックを構築することです。また、マイクロソフトにバグレポートを提出することもできます。おそらくループで繰り返し実行することで、問題を再現できるテストケースが理想的です。あなたはそれをreprosする何かを持っている場合、あなたは本当に彼らの最後にバグであることを確認した場合、それをあなたのクレジットカードを与えると、彼らはそれを請求しませんMicrosoft製品サポートサービスを呼び出すことができます。それは時間がかかりますが、機能します。がんばろう! –

関連する問題