C# HttpClient - PostAsync 没有 return(即使使用 ConfigureAwait)
C# HttpClient - PostAsync doesn't return (even with ConfigureAwait)
我对在 C# 中使用 HttpClient 非常运行...
我简化了我的项目,以便更容易地复制我的问题。我想要做的就是在后台调用 HttpClient.PostAsync 而不会阻塞我的 UI Window (顺便说一句,我正在使用 WPF)。
这是我的代码(将代码精简到最小值):
Bing 只在这里使用,不显示我的私人网络服务,当然可以用其他网站替换它。
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
try {
MyTextBlock.Text = "Waiting...";
Uri webUri = new Uri("https://www.bing.com/");
using (HttpClient client = new HttpClient()) {
using (HttpResponseMessage response = await client.PostAsync(webUri, new MultipartFormDataContent())) {
MyTextBlock.Text = await response.Content.ReadAsStringAsync();
}
}
} catch (Exception exc) {
MessageBox.Show(exc.ToString(), "Unhandled Exception");
}
}
当我的 UI 正在等待异步 post 请求时,它在文本框中显示 "Waiting"。当异步请求 returns 时,它会显示结果。不会有更多事情发生。
所以这里出现了问题,有时 PostAsync 方法根本不 return...甚至忽略超时。当我调试时,它总是有效,但当我尝试启动应用程序时,它有时会挂起。并非总是这样,这不会使查找错误变得更容易。我尝试了很多调用异步请求的方法,但每次都是同样的问题。
我还阅读了以下博客,了解异步方法中的阻塞问题,但即使使用 ConfigureAwait 也没有区别。
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
我只是可以想象在锁定主线程的 HttpClient 异步方法中存在问题,因此导致了这个问题。 Wenn 我在 ConsoleApplication 中使用相同的代码,一切都很好。我的客户和目的地之间有一个代理,但这根本不是问题。
有人可以复制这个问题吗?我在 .NET Framework 4.6.1 中使用 C#/WPF。
您不需要 await
client.PostAsync(webUri, i_formData)
因为在调用 return 之后您不会对结果做任何事情,您可以 return Task
。改成这个;
public static Task<HttpResponseMessage> BasicRequest(MultipartFormDataContent i_formData)
{
Uri webUri = new Uri("https://www.bing.com");
HttpClient client = new HttpClient {
Timeout = TimeSpan.FromSeconds(1)
};
return client.PostAsync(webUri, i_formData);
}
您的 Window_Load
是一个事件处理程序。你可以做到 async void
,这是唯一一次你不必 return Task
。通过将其设为async
,您可以删除所有过于复杂的代码:
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
MyTextBlock.Text = "Waiting";
HttpResponseMessage response = await BasicRequest(new
MultipartFormDataContent());
string test = await response.Content.ReadAsStringAsync();
this.Close();
}
首先非常感谢您的帮助,现在问题似乎已经解决了。
我必须做 3 件事才能完成这项工作:
获取一个 HttpClient 实例,在整个应用程序生命周期中使用它,因此不再使用 HttpClient。
不要在Window_Loaded事件中调用PostAsync,有时候好像来得太早了。 (我还是不明白为什么...)
不要使用 ConfigureAwait(false)
代码现在看起来像这样:
HttpClient client = new HttpClient();
private async void MyButton_Click(object sender, RoutedEventArgs e)
{
try {
MyTextBlock.Text = "Waiting...";
Uri webUri = new Uri("https://www.bing.com/");
using (HttpResponseMessage response = await client.PostAsync(webUri, new ipartFormDataContent())) {
MyTextBlock.Text = await response.Content.ReadAsStringAsync();
}
} catch (Exception exc) {
MessageBox.Show(exc.ToString(), "Unhandled Exception");
}
}
为了在启动时完成这项工作,我必须把一件非常糟糕的事情变成一件好事。但终于成功了:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
DispatcherTimer startupTimer = new DispatcherTimer();
startupTimer.Tick += new EventHandler((o, a) => {
MyFunction();
startupTimer.Stop();
});
startupTimer.Interval = TimeSpan.FromSeconds(1);
startupTimer.Start();
}
当有人可以复制这些行为或可以解释为什么会发生这些情况时,请在此处发表评论 :)
更新
问题仍然存在,但似乎只有在客户端使用某种代理时才会出现!
我对在 C# 中使用 HttpClient 非常运行...
我简化了我的项目,以便更容易地复制我的问题。我想要做的就是在后台调用 HttpClient.PostAsync 而不会阻塞我的 UI Window (顺便说一句,我正在使用 WPF)。
这是我的代码(将代码精简到最小值): Bing 只在这里使用,不显示我的私人网络服务,当然可以用其他网站替换它。
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
try {
MyTextBlock.Text = "Waiting...";
Uri webUri = new Uri("https://www.bing.com/");
using (HttpClient client = new HttpClient()) {
using (HttpResponseMessage response = await client.PostAsync(webUri, new MultipartFormDataContent())) {
MyTextBlock.Text = await response.Content.ReadAsStringAsync();
}
}
} catch (Exception exc) {
MessageBox.Show(exc.ToString(), "Unhandled Exception");
}
}
当我的 UI 正在等待异步 post 请求时,它在文本框中显示 "Waiting"。当异步请求 returns 时,它会显示结果。不会有更多事情发生。
所以这里出现了问题,有时 PostAsync 方法根本不 return...甚至忽略超时。当我调试时,它总是有效,但当我尝试启动应用程序时,它有时会挂起。并非总是这样,这不会使查找错误变得更容易。我尝试了很多调用异步请求的方法,但每次都是同样的问题。
我还阅读了以下博客,了解异步方法中的阻塞问题,但即使使用 ConfigureAwait 也没有区别。 http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
我只是可以想象在锁定主线程的 HttpClient 异步方法中存在问题,因此导致了这个问题。 Wenn 我在 ConsoleApplication 中使用相同的代码,一切都很好。我的客户和目的地之间有一个代理,但这根本不是问题。
有人可以复制这个问题吗?我在 .NET Framework 4.6.1 中使用 C#/WPF。
您不需要 await
client.PostAsync(webUri, i_formData)
因为在调用 return 之后您不会对结果做任何事情,您可以 return Task
。改成这个;
public static Task<HttpResponseMessage> BasicRequest(MultipartFormDataContent i_formData)
{
Uri webUri = new Uri("https://www.bing.com");
HttpClient client = new HttpClient {
Timeout = TimeSpan.FromSeconds(1)
};
return client.PostAsync(webUri, i_formData);
}
您的 Window_Load
是一个事件处理程序。你可以做到 async void
,这是唯一一次你不必 return Task
。通过将其设为async
,您可以删除所有过于复杂的代码:
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
MyTextBlock.Text = "Waiting";
HttpResponseMessage response = await BasicRequest(new
MultipartFormDataContent());
string test = await response.Content.ReadAsStringAsync();
this.Close();
}
首先非常感谢您的帮助,现在问题似乎已经解决了。
我必须做 3 件事才能完成这项工作:
获取一个 HttpClient 实例,在整个应用程序生命周期中使用它,因此不再使用 HttpClient。
不要在Window_Loaded事件中调用PostAsync,有时候好像来得太早了。 (我还是不明白为什么...)
不要使用 ConfigureAwait(false)
代码现在看起来像这样:
HttpClient client = new HttpClient();
private async void MyButton_Click(object sender, RoutedEventArgs e)
{
try {
MyTextBlock.Text = "Waiting...";
Uri webUri = new Uri("https://www.bing.com/");
using (HttpResponseMessage response = await client.PostAsync(webUri, new ipartFormDataContent())) {
MyTextBlock.Text = await response.Content.ReadAsStringAsync();
}
} catch (Exception exc) {
MessageBox.Show(exc.ToString(), "Unhandled Exception");
}
}
为了在启动时完成这项工作,我必须把一件非常糟糕的事情变成一件好事。但终于成功了:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
DispatcherTimer startupTimer = new DispatcherTimer();
startupTimer.Tick += new EventHandler((o, a) => {
MyFunction();
startupTimer.Stop();
});
startupTimer.Interval = TimeSpan.FromSeconds(1);
startupTimer.Start();
}
当有人可以复制这些行为或可以解释为什么会发生这些情况时,请在此处发表评论 :)
更新
问题仍然存在,但似乎只有在客户端使用某种代理时才会出现!