2013-03-12 14 views
6
  1. Jak uzyskać dostęp do nagłówków odpowiedzi, zanim cała odpowiedź zostanie zwrócona?
  2. Jak mogę odczytać strumień po jego nadejściu?
  3. Czy HttpClient jest moim najlepszym wyborem dla takiej szczegółowej kontroli odbierania odpowiedzi http?

Oto wycinek które mogłyby zilustrować moje pytanie:Przeczytaj nagłówki z HttpResponseMessage, zanim zawartość zostanie ukończona w 100%

using (var response = await _httpClient.SendAsync(request, 
    HttpCompletionOption.ResponseHeadersRead)) 
{ 
    var streamTask = response.Content.ReadAsStreamAsync(); 
    //how do I check if headers portion has completed? 
    //Does HttpCompletionOption.ResponseHeadersRead guarantee that? 
    //pseudocode 
    while (!(all headers have been received)) 
    //maybe await a Delay here to let Headers get fully populated 
    access_headers_without_causing_entire_response_to_be_received 

    //how do I access the response, without causing an await until contents downloaded? 
    //pseudocode 
    while (stremTask.Resul.?) //i.e. while something is still streaming 
    //? what goes here? a chunk-read into a buffer? or line-by-line since it's http? 
    ... 


Edycja wyjaśnienie kolejną szarą strefę dla mnie:
Wszelkie odniesienia I odkryła ma jakieś oświadczenie blokującym, to spowodowałoby oczekiwanie na przybycie zawartości. Odwołania Czytam zwykle dostęp do metod lub właściwości na streamTask.Result lub na Treści, i nie wiem wystarczająco dużo, aby wykluczyć, które odnośniki są w porządku, jak działanie streamTask vs, które będą powodować oczekiwanie aż do zadanie się kończy.

+0

pisałem odpowiedź, ale potem sobie sprawę, że było to nieco źle zbadane i leniwy. Zamiast tego mam pytanie uzupełniające, co rozumiesz przez blokowanie oświadczenia? Wszystkie operacje HttpClient są asynchroniczne, nie powinno być nic, co powstrzymałoby cię od czytania nagłówków i strumienia treści w oddzielnych zadaniach, uniemożliwiając im wzajemne blokowanie się. – Snixtor

+0

@Snixtor, moje pytanie prawdopodobnie bazuje na błędnym założeniu, że jeśli wyraźnie czekam na dostęp do stremTask.Result, sprawię, że cała zawartość zostanie odczytana. Ostatecznie szukałem instalacji do A), przeczytałem nagłówki, B) przeczytałem strumień, jak to jest Będę edytować moje pytanie za pomocą pseudokodu w celu zilustrowania tego, co sobie wyobrażam. –

+0

Masz rację, to niepoprawne założenie. 'streamTask.Result' będzie blokował, dopóki' Stream' nie będzie dostępny, ale nie wymaga, aby cała zawartość strumienia została już przesłana. Technicznie może być dostępnych zero bajtów dostępnych po wywołaniu 'streamTask.Result'. – Snixtor

Odpowiedz

4

Na podstawie własnych testów treść nie zostanie przesłana, dopóki nie zaczniesz czytać strumienia treści, i masz rację, że wywołanie Task.Result jest blokowaniem, ale z samej swojej natury jest punktem synchronizacji. Ale, nie blokuje do wstępnego buforowania całej zawartości, blokuje tylko do momentu, aż zawartość rozpocznie się pochodzić z serwera.

Tak więc nieskończony strumień nie zostanie zablokowany na nieskończenie długi czas. W związku z tym próba pobrania strumienia asynchronicznie może zostać uznana za nadmierną, szczególnie jeśli operacja przetwarzania nagłówka jest stosunkowo krótka. Ale jeśli chcesz, zawsze możesz przetworzyć nagłówki, podczas gdy strumień treści jest przetwarzany na inne zadanie. Coś takiego mogłoby to osiągnąć.

static void Main(string[] args) 
{ 
    var url = "http://somesite.com/bigdownloadfile.zip"; 
    var client = new HttpClient(); 
    var request = new HttpRequestMessage(HttpMethod.Get, url); 

    var getTask = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); 
    Task contentDownloadTask = null; 

    var continuation = getTask.ContinueWith((t) => 
    { 
     contentDownloadTask = Task.Run(() => 
     { 
      var resultStream = t.Result.Content.ReadAsStreamAsync().Result; 
      resultStream.CopyTo(File.Create("output.dat")); 
     }); 

     Console.WriteLine("Got {0} headers", t.Result.Headers.Count()); 
     Console.WriteLine("Blocking after fetching headers, press any key to continue..."); 
     Console.ReadKey(true); 
    }); 

    continuation.Wait(); 
    contentDownloadTask.Wait(); 
    Console.WriteLine("Finished downloading {0} bytes", new FileInfo("output.dat").Length); 

    Console.WriteLine("Finished, press any key to exit"); 
    Console.ReadKey(true); 
} 

Zauważ, że nie ma potrzeby, aby sprawdzić, czy część nagłówków jest kompletna, już wyraźnie określono, że z opcją HttpCompletionOption.ResponseHeadersRead. Zadanie SendAsync nie będzie kontynuowane, dopóki nagłówki nie zostaną odzyskane.

+0

Co powiesz na czytanie strumienia w porcjach - buforze lub łańcuchach/liniach? Czy HttpClient jest najbardziej odpowiednią klasą dla tak szczegółowej kontroli pobierania http? –

+1

Aby przeczytać fragmenty, można użyć 'Stream.Read' - http://msdn.microsoft.com/en-us/library/system.io.stream.read.aspx - Chociaż potrzebna jest dość konkretna sytuacja, aby uzasadnij to (może być trochę niezgrabny i powolny w porównaniu z 'CopyTo' .Jeśli chcesz czytać wiersz po linii, zawiń strumień w' StreamReader' - http://msdn.microsoft.com/pl -us/library/system.io.streamreader.aspx – Snixtor

+1

Jeśli chodzi o 'HttpClient', po otrzymaniu strumienia zawartości odpowiedzi jest on zupełnie nieaktualny, zarządza żądaniem i odpowiedzią, nagłówkami, przetwarzaniem błędów itp. Nie uzyskasz większej elastyczności niż bezpośredni dostęp do strumienia odpowiedzi, przynajmniej nie w zarządzanym kodzie. – Snixtor

3

Wynik używając czekają/async słów kluczowych jest jeszcze bardziej czytelny:

var url = "http://somesite.com/bigdownloadfile.zip"; 

using (var httpClient = new HttpClient()) 
using (var httpRequest = new HttpRequestMessage(HttpMethod.Get, url)) 
using(HttpResponseMessage response = await httpClient.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead)) 
using (Stream stream = await response.Content.ReadAsStreamAsync()) 
{ 
    //Access to the Stream object as it comes, buffer it or do whatever you need 
}  
Powiązane problemy