2013-05-21 20 views
10

Gziplenmiş kodlanmış istekleri destekleyen bir sunucuya bir http posta isteği için hacimli veri göndermem gerekir.http isteklerini anında ve sıkıştırılmış arabellek belleğe yüklemeden nasıl sıkıştırılır

basit

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

başlayarak Sadece bir ön sıkıştırma

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

ekledik Mükemmel ancak veriler tamamen isteğini göndermeden önce belleğe yüklenir sıkıştırmak çalışır. I , akış halinde gönderim sırasında anında veriyi sıkıştırmak isteyebilir. Bunu yapmak için

, kod aşağıdaki denedim:

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

ama copyToAsync (GZipStream) dışına gitmez. FlushAsync hiçbir zaman yürütülmez ve istisna atılmaz ve Fiddler herhangi bir gönderi başlatmaz.

Sorularım şunlardır:

  • CompressAsync2 çalışmıyor neden?
  • Bellekte sıkıştırılmış arabellek yükleme ve yükleme sırasında anında nasıl sıkıştırılır?

Herhangi bir yardım çok takdir edilecektir.

+1

'PushStreamContent' (şu anda) 'async' lambda'larını desteklemiyor. –

+0

@Stephen Cleary: Haklısınız, kontrol etmeliydim! Ve SerializeToStreamAsync'i (yalnızca çok fazla dahili) aşırı yüklemek için PushStreamContent'ten türemem. bir çözüm görebiliyor musun? – MuiBienCarlota

+0

Hmm, sadece ['PushStreamContent 'almak ve değiştirmek için] (https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Net.Http.Formatting/PushStreamContent.cs) desteklemek için en kolay olabilir async' lambdas. Birkaç aydır "todo" listemdeydi, sadece etrafta dolanmadım. –

cevap

12

P.S. WebAPIContrib https://github.com/WebApiContrib/WebAPIContrib/blob/master/src/WebApiContrib/Content/CompressedContent.cs den

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

CompressedContent sınıfını kullanmayı deneyin Bunun sadece .net 4.5'deki içeriği yayınlayacağını. HttpWebRequest .net 4 sürümü her zaman arabellekleri içerik gönderdi.

P.P.S. Her istek için yeni bir HttpClient oluşturmak, HttpClient'i kullanmanın en iyi yolu değildir. Bunu yapmak, her istek için yeni bir TCP bağlantısı oluşturulmasını zorlayacaktır.

+0

Gerçekten iç içe geçen bağlantı: çok teşekkürler. Net 4.0 (XP gerekli) üzerinde kalmam gerekiyor. .Net 4.0 için derlediğim halde .Net 4.5 kurulduğunda, akışa geçebileceğimi düşünüyor musunuz? – MuiBienCarlota

+0

Sadece soru basitliği için yerel bir HttpClient oluşturdum. – MuiBienCarlota

+0

@MuiBienCarlota Emin değilim. Tahminim evet olurdu, ama test etmeniz gerekiyor. HttpClient ile ilgili olarak ... havalı, ben sadece çok görüyorum ve bunu çıkarmak için bir görevdeyim ;-) –

İlgili konular