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 件事才能完成这项工作:

  1. 获取一个 HttpClient 实例,在整个应用程序生命周期中使用它,因此不再使用 HttpClient。

  2. 不要在Window_Loaded事件中调用PostAsync,有时候好像来得太早了。 (我还是不明白为什么...)

  3. 不要使用 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();
}

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


更新

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