【问题标题】:http client frozes in windows form apphttp客户端在Windows窗体应用程序中冻结
【发布时间】:2014-08-10 14:13:57
【问题描述】:

我正在关注this example,它可以在控制台应用程序中运行,但后来我尝试在 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);
            }

        }
    }

【问题讨论】:

  • 为什么您的 button1_Click 仍在尝试写入控制台?它不再是控制台应用程序。
  • @KenWhite 是的,我的错,忘了那行,我正在尝试从我的 api 中获取一些“分支”,然后客户应该返回他喜欢的那些

标签: c# httpclient asp.net-web-api async-await


【解决方案1】:

您看到了我explain fully on my blog 的死锁。本质上,await 将捕获“上下文”并使用它来恢复 async 方法。在 Console 应用中,这个“上下文”是线程池上下文,但在 UI 应用中,这个“上下文”是 UI 线程上下文。

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

要解决这个问题,请一直使用async

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 下载完成后你想做什么?
    • 我的应用会读取一个分支列表,然后客户端会选择其中的一些分支,我应该把它放在哪里?
    • 您可以禁用在 HTTP 请求完成之前不应与之交互的任何表单元素(例如分支的 ListBox),然后在 RunAsync() 的末尾重新启用该元素。见danderson.me/posts/…
    【解决方案3】:

    如果您在 Windows 窗体中执行此代码,那么您应该使用 Messagebox.Show("Fetching data") 并且您会看到它会延迟 Main 退出。到这个时候你的回应就会来了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-21
      • 2014-02-28
      相关资源
      最近更新 更多