HTTP客户端在Windows表单应用程序中冻结

本文关键字:应用程序 冻结 表单 Windows 客户端 HTTP | 更新日期: 2023-09-27 18:09:39

我遵循这个例子,它在控制台应用程序中工作,但后来我在windows窗体应用程序中尝试了它,当它击中await client.GetAsync("api/branches/1035")行时有什么不同?

控制台代码(这个有效):

static void Main()
    {
        RunAsync().Wait();
    }
    static async Task RunAsync()
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri("http://localhost:49358/");
           client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            HttpResponseMessage response = await client.GetAsync("api/branches/1035");
            if (response.IsSuccessStatusCode)
            {
                branch branch = await response.Content.ReadAsAsync<branch>();
                Console.WriteLine("{0}'t${1}", branch.Id, branch.Color);
            }
        }
    }

在到达await client.GetAsync("api/branches/1035")

时被冻结
private void button1_Click(object sender, EventArgs e)
    {
        RunAsync().Wait();
    }
    static async Task RunAsync()
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri("http://localhost:49358/");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            HttpResponseMessage response = await client.GetAsync("api/branches/1035");
            if (response.IsSuccessStatusCode)
            {
                Branch branch = await response.Content.ReadAsAsync<Branch>();
                Console.WriteLine("{0}'t${1}", branch.Id, branch.Color);
            }
        }
    }

HTTP客户端在Windows表单应用程序中冻结

您看到的是一个死锁,我在我的博客上详细解释过。本质上,await将捕获一个"上下文"并使用它来恢复async方法。在控制台应用中,这个"context"是线程池上下文,但在UI应用中,这个"context"是UI线程上下文。

在调用堆栈的更上层,您调用Wait,它阻塞该线程直到任务完成。在控制台应用程序中,async方法在线程池线程上恢复;但是在UI应用程序中,async方法不能在UI线程上恢复(因为UI线程在调用Wait时被阻塞了)。

要解决这个问题,使用async:

private async void button1_Click(object sender, EventArgs e)
{
  await RunAsync();
}

您正在等待异步任务的结果。阻塞UI线程,直到该任务完成。

不要在button1_Click事件处理程序中等待完成。

如果你在Windows窗体中执行这段代码,那么你应该使用Messagebox.Show("抓取数据"),你会看到它会延迟Main退出。此时您的回复将会到来。