2013-05-21 29 views
10

Tôi cần gửi dữ liệu đồ sộ trong yêu cầu đăng http lên máy chủ hỗ trợ yêu cầu được mã hóa gzip.Cách nén yêu cầu http khi đang di chuyển và không tải bộ đệm nén vào bộ nhớ

Bắt đầu từ một đơn giản

public async Task<string> DoPost(HttpContent content) 
{ 
    HttpClient client = new HttpClient(); 
    HttpResponseMessage response = await client.PostAsync("http://myUri", content); 

    response.EnsureSuccessStatusCode(); 
    return await response.Content.ReadAsStringAsync(); 
} 

Tôi vừa mới bổ sung thêm một nén trước

public async Task<string> DoPost(HttpContent content, bool compress) 
{ 
    if (compress) 
    content= await CompressAsync(content); 

    return await DoPost(content); 
} 

private static async Task<StreamContent> CompressAsync(HttpContent content) 
{ 
    MemoryStream ms = new MemoryStream(); 
    using (GZipStream gzipStream = new GZipStream(ms, CompressionMode.Compress, true)) 
    { 
    await content.CopyToAsync(gzipStream); 
    await gzipStream.FlushAsync(); 
    } 

    ms.Position = 0; 
    StreamContent compressedStreamContent = new StreamContent(ms); 
    compressedStreamContent.Headers.ContentType = content.Headers.ContentType; 
    compressedStreamContent.Headers.Add("Content-Encoding", "gzip"); 

    return compressedStreamContent; 
} 

Nó hoạt động một cách hoàn hảo nhưng nén dữ liệu được hoàn toàn nạp vào bộ nhớ trước khi gửi yêu cầu. Tôi muốn có thể nén dữ liệu khi đang di chuyển trong khi đang phát trực tuyến.

Để làm điều đó, tôi đã cố gắng mã sau:

private static async Task<HttpContent> CompressAsync2(HttpContent content) 
{ 
    PushStreamContent pushStreamContent = new PushStreamContent(async (stream, content2, transport) => 
    { 
    using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Compress, true)) 
    { 
     try 
     { 
     await content.CopyToAsync(gzipStream); 
     await gzipStream.FlushAsync(); 
     } 
     catch (Exception exception) 
     { 
     throw; 
     } 
    } 
    }); 
    pushStreamContent.Headers.ContentType = content.Headers.ContentType; 
    pushStreamContent.Headers.Add("Content-Encoding", "gzip"); 

    return pushStreamContent; 
} 

nhưng nó không bao giờ đi ra khỏi CopyToAsync (gzipStream). FlushAsync không bao giờ được thực thi và không có ngoại lệ nào được ném và Fiddler không thấy bất kỳ bài đăng nào được bắt đầu.

Câu hỏi của tôi là:

  • Tại sao CompressAsync2 không hoạt động?
  • Cách nén khi đang di chuyển trong khi gửi và không tải bộ đệm nén trong bộ nhớ?

Mọi trợ giúp sẽ được đánh giá cao.

+1

'PushStreamContent' không (hiện tại) hỗ trợ' async' lambdas. –

+0

@Stephen Cleary: Bạn đã đúng, tôi nên đã kiểm tra! Và tôi không thể bắt nguồn từ PushStreamContent đến quá tải SerializeToStreamAsync (quá nhiều chỉ nội bộ). bạn có thấy giải pháp không? – MuiBienCarlota

+0

Humm, có thể dễ dàng nhất để lấy ['PushStreamContent' và sửa đổi nó] (https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Net.Http.Formatting/PushStreamContent.cs) để hỗ trợ' async' lambdas. Nó đã được vào danh sách "todo" của tôi cho một vài tháng nay, chỉ cần không nhận được xung quanh với nó. –

Trả lời

12

Hãy thử sử dụng các lớp CompressedContent từ WebAPIContrib https://github.com/WebApiContrib/WebAPIContrib/blob/master/src/WebApiContrib/Content/CompressedContent.cs

public async Task<string> DoPost(HttpContent content) 
{ 
    HttpClient client = new HttpClient(); 
    HttpResponseMessage response = await client.PostAsync("http://myUri", new CompressedContent(content,"gzip")); 

    response.EnsureSuccessStatusCode(); 
    return await response.Content.ReadAsStringAsync(); 
} 

T.B. rằng điều này sẽ chỉ phát trực tuyến nội dung trên .net 4.5. Phiên bản .net 4 của HttpWebRequest luôn là bộ đệm gửi nội dung.

P.P.S. Tạo một HttpClient mới cho mỗi yêu cầu không phải là cách tốt nhất để sử dụng HttpClient. Làm như vậy sẽ buộc một kết nối TCP mới được tạo cho mỗi yêu cầu.

+0

Liên kết gián đoạn thực sự: cảm ơn rất nhiều. Tôi cần phải ở lại .Net 4.0 (XP cần thiết). Bạn có nghĩ rằng tôi có thể được phát trực tiếp khi .Net 4.5 được cài đặt ngay cả khi tôi biên dịch .Net 4.0 không? – MuiBienCarlota

+0

Tôi đã tạo một HttpClient cục bộ chỉ cho câu hỏi đơn giản. – MuiBienCarlota

+0

@MuiBienCarlota Tôi không chắc chắn. Tôi đoán là có, nhưng bạn cần phải kiểm tra. Về HttpClient ... mát mẻ, tôi chỉ nhìn thấy nó rất nhiều và tôi đang trên một nhiệm vụ để đóng dấu nó ra ;-) –

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