2013-03-12 7 views
6
  1. 応答ヘッダーにアクセスするにはどうすればよいですか?
  2. ストリームの到着時にストリームを読み取るにはどうすればよいですか?
  3. HTTP応答を受信するようなきめ細かな制御のためにHttpClientが最良の選択ですか? 、私は発掘
    いずれの参照がブロッキング文のいくつかの種類があります:私のために別の灰色の領域を明確にするために

    コンテンツが100%完成する前にHttpResponseMessageからヘッダーを読み取る

    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? 
        ... 
    


    編集

は、ここに私の質問を説明するかもしれないスニップです内容が到着するのを待つ原因となる。 参考文献私は通常、streamTask.ResultまたはContentのアクセスメソッドまたはプロパティを読み込み、streamTaskが進行中であるときにそのような参照が大丈夫であるかどうかを判断するのに十分ではないタスクが完了しました。

+0

私は答えを書いたが、少し研究し、病気や怠惰に気づきました。代わりに私はフォローアップの質問をしています、あなたは文をブロックすることによってどういう意味ですか?すべてのHttpClient操作が非同期であるため、ヘッダーとコンテンツストリームを別々のタスクで読み取ることを妨げるものがあってはなりません。 – Snixtor

+0

@Snixtor、私の質問はおそらく私が明示的にstremTask.Resultを待っている、またはアクセスする場合、私は全体の内容が読み取られる原因になるという誤った仮定に基づいているでしょう。 最終的に私はA)への配管を探していました。ヘッダーを読んでください。B)ストリームが来るように読んでください。 想像していることを説明するために擬似コードで質問を編集します。 –

+0

あなたは正しい、それは間違った前提です。 'streamTask.Result'は' Stream'が利用可能になるまでブロックしますが、ストリームの内容全体が既に転送されていることを要求しません。技術的には、 'streamTask.Result'を呼び出した後、使用可能なコンテンツバイトがゼロになることがあります。 – Snixtor

答えて

4

私自身のテストに基づいて、コンテンツストリームの読み取りを開始するまではコンテンツは転送されず、Task.Resultという呼び出しがブロッキングコールであることが間違いありませんが、その性質上、同期点です。 しかしは、コンテンツ全体をプリバッファリングするのをブロックしません。コンテンツがサーバから来るようになるまでブロックします。

無限のストリームは無限の時間ブロックされません。そのため、ストリームを非同期的にフェッチしようとすると、特にヘッダー処理操作が比較的短い場合には、過剰なものとみなされる可能性があります。しかし、必要ならば、コンテンツストリームが別のタスクで処理されている間は、常にヘッダーを処理できます。これのようなものはそれを達成するでしょう。ヘッダ部分が完了したかどうかを確認する必要がないことを

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

注は、明示的にHttpCompletionOption.ResponseHeadersReadオプションであることを指定しました。 SendAsyncタスクは、ヘッダーが取得されるまで続行されません。

+0

バッファや文字列/行のチャンクでストリームを読むのはどうですか? HTTPダウンロードのようなきめ細かな制御のためにHttpClientが最も適切なクラスですか? –

+1

チャンクを読み込むには 'Stream.Read'を使うことができます - http://msdn.microsoft.com/en-us/library/system.io.stream.read.aspx - あなたはかなり特別な状況が必要ですそれを正当化します( 'CopyTo'と比較して少し不器用で遅いことがあります)。行ごとに読みたい場合は、' StreamReader'でストリームをラップしてください - http://msdn.microsoft.com/ja -us/library/system.io.streamreader.aspx – Snixtor

+1

'HttpClient'に関しては、いったんレスポンスコンテンツストリームを取得すると、それはピクチャから外れています。要求と応答、ヘッダー、エラー処理などを管理します。レスポンスストリームに直接アクセスするよりも、管理されたコードではなく、はるかに柔軟性を得ることはありません。 – Snixtor

3

結果は、それがさらに読みやすいのawait /非同期のキーワードを使用して:

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 
}  
関連する問題