13
  1. 応答全体がストリーミングされる前に、応答ヘッダーにアクセスするにはどうすればよいですか?
  2. ストリームが到着したときにどのように読むのですか?
  3. HttpClient は、http 応答の受信をきめ細かく制御するための最良の選択ですか?

ここに私の質問を説明するかもしれないスニップがあります:

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 が進行しているときにどのような参照が問題ないか、タスクが完了するまで待機を引き起こす可能性がある参照を除外するのに十分な情報がありません。完了します。

4

2 に答える 2

7

私自身のテストに基づいて、コンテンツ ストリームの読み取りを開始するまでコンテンツは転送されません。呼び出し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ヘッダーが取得されるまで、タスクは続行されません。

于 2013-03-13T01:35:14.450 に答える
6

await/async キーワードを使用した結果は、さらに読みやすくなっています。

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
}    
于 2013-10-18T14:06:59.977 に答える