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);
}
}
}
您看到的是一个死锁,我在我的博客上详细解释过。本质上,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退出。此时您的回复将会到来。