C#HttpClient - PostAsync不会返回(即使使用ConfigureAwait)

时间:2017-10-30 08:52:00

标签: c# wpf async-await httpclient blocking

我在C#中使用HttpClient时感到很疯狂......

我简化了我的项目,因此可以更轻松地复制我的问题。我想做的就是在后台调用HttpClient.PostAsync而不阻塞我的UI窗口(我正在使用WPF btw)。

这是我的代码(将代码删到了min。): 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正在等待异步发布请求时,它会显示"等待"在TextBox中。当异步请求返回时,它会显示结果。什么都不应该发生。

所以这里出现问题,有时候PostAsync方法根本就不会返回......甚至会忽略Timeout。当我调试它总是有效,但当我尝试启动应用程序时,它有时会挂起。并不总是哪个不能让错误更容易找到。我尝试了很多方法来调用请求异步,但每次都是同样的问题。

我还在异步方法中阅读了关于阻止问题的博客,但即使是ConfigureAwait,也没有区别。 http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

我可以想象HttpClient异步方法中存在一个问题,锁定主线程,因此导致了这个问题。 Wenn我在ConsoleApplication中使用相同的代码一切都很好。我的客户和目的地之间有一个代理,但这根本不是问题。

有人可以复制这个问题吗?我在.NET Framework 4.6.1中使用C#/ WPF。

2 个答案:

答案 0 :(得分:5)

您不需要await client.PostAsync(webUri, i_formData)因为您在调用返回后没有对结果执行任何操作,您只需返回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,这是您不必返回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();
}

答案 1 :(得分:0)

首先,谢谢你的帮助,现在问题似乎已经解决了。

我必须做3件事来完成这项工作:

  1. 获取HttpClient的一个实例,在整个应用程序生命周期内使用它,所以不再使用HttpClient。

  2. 不要在Window_Loaded事件中调用PostAsync,有时似乎要早。 (我仍然不明白为什么......)

  3. 请勿使用ConfigureAwait(false)

  4. 代码现在看起来像这样:

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

    当有人可以复制这些行为或者可以解释为什么会发生这些行为时,请在此处对其进行评论:)

    <强>更新

    问题仍然存在,但似乎只有当客户端使用某种代理时才会出现问题!