【问题标题】:Using await on HttpClient in wpf project在 wpf 项目中的 HttpClient 上使用 await
【发布时间】:2016-10-05 03:36:12
【问题描述】:

我只是按照一个示例在同步模式下调用 HttpClient,它在控制台应用程序中运行良好。

但是,当我将其移至 wpf 应用程序时,程序挂起,没有任何返回。

我尝试通过构建一个单独的类来处理访问 www.google.com 的虚拟请求来隔离问题。

应用程序似乎在调用client.GetAsync时挂起,请问在这种情况下是否需要将控制台应用程序更改为wpf?

请在下面找到控制台应用程序和 wpf 的源代码,

控制台应用程序 - 工作正常:

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

namespace ca03
{
    static class action
    {
        static async Task<string> DownloadPageAsync()
        {
            // ... Target page.
            string page = "http://www.google.com/";

            // ... Use HttpClient.
            using (HttpClient client = new HttpClient())
            using (HttpResponseMessage response = await client.GetAsync(page))
            using (HttpContent content = response.Content)
            {
                // ... Read the string.
                string result = await content.ReadAsStringAsync();

                // ... Display the result.
                if (result != null &&
                result.Length >= 50)
                {
                    Console.WriteLine(result.Substring(0, 50) + "...");
                }
                return result;
            }
        }

        public static string goDownload()
        {
            Task<string> x = DownloadPageAsync();
            string result = x.Result;
            return result;
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            string data = action.goDownload();
            Console.WriteLine(data);

            Console.ReadLine();
        }
    }
}

WPF 应用程序:(只是一个添加了按钮的普通项目)- 挂在 GetAsync

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

namespace wpf02
{

    static class action
    {
        static async Task<string> DownloadPageAsync()
        {
            // ... Target page.
            string page = "http://www.google.com/";

            // ... Use HttpClient.
            using (HttpClient client = new HttpClient())
            using (HttpResponseMessage response = await client.GetAsync(page))
            using (HttpContent content = response.Content)
            {
                // ... Read the string.
                string result = await content.ReadAsStringAsync();
                return result;
            }
        }

        public static string goDownload()
        {
            Task<string> x = DownloadPageAsync();
            string result = x.Result;
            return result;
        }

    }


    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void button_Click(object sender, RoutedEventArgs e)
        {
            string data = action.goDownload();
            Console.WriteLine(data);
        }
    }
}

【问题讨论】:

  • 我更详细地探讨了这个问题on my blog

标签: c# wpf async-await httpclient


【解决方案1】:

这行是问题所在:

string result = x.Result;

当您使用Result 属性时,会阻塞当前线程,直到任务完成。当您的延续计划在同一个线程上运行时,这是一个问题......

基本上,您的 goDownload 方法没有意义 - 只需将您的 DownloadPageAsync 方法更改为公开,然后将您的 button_Click 方法更改为异步,这样您就可以等待结果:

private async void button_Click(object sender, RoutedEventArgs e)
{
    string data = await action.DownloadPageAsync();
    Console.WriteLine(data);
}

【讨论】:

  • 感谢您的建议。如果我按照您的建议修改代码,它工作正常。但是,这是我现有应用程序的结构,类动作实际上来自一个单独的库项目,我想通过直接从该方法获取字符串来简化调用者的代码。在我的应用程序中,goDownload 将从由计时器事件触发的后台线程调用。有没有办法像上面那样构建一个像goDownload这样的实用函数,这样调用者就可以直接使用这个方法来接收一个字符串,而无需添加async/await。
  • @James:如果你想要一个阻塞调用,你基本上必须把整个事情放到后台线程中。但从根本上说,你现在是从 UI 线程调用该方法 - 你真的不应该阻止 UI 线程进行网络操作。
  • 非常感谢。我只是尝试使用上面的示例来简化案例,因此它是从 UI 线程的按钮单击调用的。刚刚又找了一个例子,好像直接从GetAcync(page).Result得到结果,会以同步模式执行。但我不知道它是否在后台线程下工作。我将修改我的项目进行测试。
  • 虽然这不完全是我的要求,但我从你的解决方案中得到了一些想法来解决我的问题。所以我用你的建议结束这个问题。非常感谢。
【解决方案2】:

顶级原因 - WPF(与任何 UI 应用程序一样)有一个 UI 线程,可与 winwdows 循环队列一起使用。 Jon Skeet 给你一个最简单的设计,但你可以使用 CLR ThreadPool 中的线程:

            Task<string> t = Task.Run(() => DownloadPageAsync());
        string result =  = await t;

【讨论】:

  • 非常感谢。虽然这不是我正在寻找的,但它给了我以不同方法制作所需功能的想法,我现在了解了更多关于 WPF UI 线程的信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-02
  • 2013-03-30
  • 1970-01-01
  • 1970-01-01
  • 2021-10-03
  • 2016-01-29
  • 2021-07-20
相关资源
最近更新 更多