2012-11-23 26 views
6

Tôi có một ASP.Net Web API được thiết lập trên trang web của tôi được sử dụng để giao tiếp với một ứng dụng máy tính để bàn WPF. Tôi có một thiết lập hành động trên API để nhận tệp nhị phân từ ứng dụng khách. Tuy nhiên trong một số trường hợp (dường như ngẫu nhiên) khi tôi nhận được tất cả các byte từ yêu cầu, không phải tất cả các byte đều được đọc. Hy vọng rằng bạn có thể cho tôi một ý tưởng làm thế nào để làm điều này theo một cách mà sẽ làm việc tất cả các thời gian. Dưới đây là các mã:ASP.Net Web API không đọc tất cả các byte từ StreamContent

Client Side:

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 là một enum định nghĩa kết quả trên máy chủ, turnId là ID cho đơn vị tập tin này được gắn vào, và fileStream là một FileStream thực tế đọc các byte của đĩa.

Server Side:

[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

Đây có phải là Windows Server 2003 hoặc Windows XP 32 bit không? Chúng tôi đang chạy vào cùng một hành vi này với StreamContent, nhưng khi phát trực tuyến phản hồi từ dịch vụ Web API của Windows Server 2003. Nó không repro vào năm 2008. Ngoài ra, chúng tôi đã tìm thấy rằng điều này chỉ repros với một FileStream. Chuyển đổi FileStream thành MemoryStream bỏ qua vấn đề (với chi phí bộ nhớ của khóa học). Chúng tôi đã nhận thấy rằng khi luồng phản hồi chấm dứt sớm, nó luôn ở ranh giới 4096 byte và nó đạt đến giới hạn khoảng 3,5MB. –

Trả lời

11

Như đã nêu trong bình luận trước đây của tôi, chúng tôi chạy vào hành vi này cùng với StreamContent, nhưng khi trình chiếu một phản hồi từ một Server 2003 dịch vụ Windows Web API. Nó không repro vào năm 2008. Trên thực tế, nó cũng repros trên Windows Server 2008 nếu tôi cấu hình máy ảo với một số lượng nhỏ RAM (712 MB), nhưng với 4 GB RAM nó không repro. Ngoài ra, chúng tôi thấy rằng điều này chỉ repros với một FileStream. Chuyển đổi FileStream thành MemoryStream bỏ qua vấn đề (với chi phí bộ nhớ của khóa học). Chúng tôi nhận thấy rằng khi luồng phản hồi kết thúc sớm, nó luôn nằm trên ranh giới 4096 byte và đạt đến giới hạn khoảng 3,5MB.

Dưới đây là cách khắc phục điều cố định đối với tôi, phù hợp với ví dụ mã của bạn:

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

Nếu muốn, bạn có điều kiện có thể làm MemoryStream sao chép chỉ khi Stream là một FileStream.

+0

Cảm ơn bạn đã đề xuất, rất tiếc, nó không giải quyết được vấn đề cho tôi. Phần khách hàng của mã đang chạy trên hàng trăm máy từ WinXP đến Win8.1 và tôi đã thay đổi nó để sử dụng MemoryStream thay vì một FileStream. Phần máy chủ của nó đang chạy trên WinServer 2012R2. Tôi vẫn gặp vấn đề bây giờ và sau đó, nơi số byte đọc từ luồng nội dung bởi máy chủ không khớp với số lượng byte được gửi bởi máy khách = \ –

+0

Điều đó thực sự không may, và không tốt cho giải pháp của tôi "có vẻ như đang làm việc cho tôi cho đến nay. Điều tốt nhất có thể thực hiện trong trường hợp của bạn là xây dựng logic thử lại phía máy khách nếu phản hồi HTTP không thành công. Hoặc gửi báo cáo lỗi với Microsoft, lý tưởng với một trường hợp kiểm tra có thể sửa đổi vấn đề, có thể bằng cách chạy lặp lại trong một vòng lặp. Nếu bạn có thứ gì đó repros nó, bạn có thể gọi lên dịch vụ hỗ trợ sản phẩm của Microsoft, cung cấp cho họ thẻ tín dụng của bạn, và họ sẽ không tính phí nếu họ xác nhận rằng nó thực sự là một lỗi về kết thúc của họ. Đó là thời gian, nhưng nó hoạt động. Chúc may mắn! –

Các vấn đề liên quan