我只是按照一个示例在同步模式下调用 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;