web-dev-qa-db-ja.com

Visual Studioで非同期のHttpClient.GetAsync()を呼び出した後にデバッガーが停止する

次のHTTPリクエストメソッドをテストしようとしています

public async Task<HttpContent> Get(string url)
    {
        using (HttpClient client = new HttpClient())
// breakpoint
        using (HttpResponseMessage response = await client.GetAsync(url))
// can't reach anything below this point
        using (HttpContent content = response.Content)
        {
            return content;
        }
    }

ただし、デバッガーは2番目のコメントの下のコードをスキップしているようです。 Visual Studio 2015 RCを使用していますが、何かアイデアはありますか?また、[タスク]ウィンドウを確認しても何も表示されませんでした

編集:解決策を見つけた

using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace ConsoleTests
{
    class Program
    {
        static void Main(string[] args)
        {
            Program program = new Program();
            var content = program.Get(@"http://www.google.com");
            Console.WriteLine("Program finished");
        }

        public async Task<HttpContent> Get(string url)
        {
            using (HttpClient client = new HttpClient())
            using (HttpResponseMessage response = await client.GetAsync(url).ConfigureAwait(false))
            using (HttpContent content = response.Content)
            {
                return content;
            }
        }
    }
}

これはC#コンソールアプリだったので、メインスレッドの終了後に終了したことがわかりました。これは、Console.ReadLine()を追加して少し待った後、リクエストが返されたためです。 C#はタスクが実行されるまで待機し、タスクが終了するまで待機しないと思っていましたが、私は間違っていたと思います。なぜこれが起こったのかについて誰かが詳しく説明できれば、それは素晴らしいことです。

28
sgarcia.dev

Mainが終了すると、プログラムが終了します。未処理の非同期操作はキャンセルされ、その結果は破棄されます。

したがって、Mainの終了をブロックする必要があります。これは、非同期操作または他のメソッドでブロックすることで行います(たとえば、Console.ReadKeyを呼び出して、ユーザーがキーを押すまでブロックします)。

static void Main(string[] args)
{
  Program program = new Program();
  var content = program.Get(@"http://www.google.com").Wait();
  Console.WriteLine("Program finished");
}

一般的なアプローチの1つは、例外処理も行うMainAsyncを定義することです。

static void Main(string[] args)
{
  MainAsync().Wait();
}

static async Task MainAsync()
{
  try
  {
    Program program = new Program();
    var content = await program.Get(@"http://www.google.com");
    Console.WriteLine("Program finished");
  }
  catch (Exception ex)
  {
    Console.WriteLine(ex);
  }
}

非同期コードでのブロックは一般に悪い考えであることに注意してください。実行する必要があるケースは非常に少なく、コンソールアプリケーションのMainメソッドはたまたまその1つです。

37
Stephen Cleary