在 wpf 项目中的 HttpClient 上使用 await



我只是按照一个示例在同步模式下调用 HttpClient,它在控制台应用程序中工作正常。

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

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

似乎应用程序挂起在调用客户端中。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);
        }
    }
}

这一行是问题所在:

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);
}

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

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

最新更新