【问题标题】:Application enter in a "wait status" while HttpRequest operation应用程序在 HttpRequest 操作时进入“等待状态”
【发布时间】:2026-01-14 10:00:02
【问题描述】:

我正在对一个返回 xml 内容的 Url 执行 HttpRequest。所以我尝试发出一个异步请求,但是在这个请求期间应用程序被停止(暂停)并且它似乎无法获得响应(浏览器内的 url 工作正常,它返回我所期望的)。

这是我的代码:

public static async Task<String> getResponse(String url)
{
    HttpClient httpClient = new HttpClient();
    HttpResponseMessage request = await httpClient.GetAsync(url);
    String stream = await request.Content.ReadAsStringAsync();
    return stream;
}

我认为这是:

String response = UtilityClass.getResponse(requestUrl).Result;

谁能帮帮我?

【问题讨论】:

  • 你说你没有得到回应是什么意思?响应只是空的吗?它会抛出异常还是什么?你得到什么状态码?

标签: c# asynchronous request httprequest async-await


【解决方案1】:

这里发生的是死锁。在没有太多信息的情况下,我看到您在调用时阻塞了异步操作

string response = UtilityClass.getResponse(requestUrl).Result

发生的情况是,当您在 getResponse 中使用 await 时,正在生成的 TaskAwaitable 会捕获您的 SynchronizationContext,以便将延续编组回到调用它的同一上下文中。但是,当它试图将工作 bacl 编组到捕获的上下文时它不能,因为Result 正在阻塞线程。这就是为什么你应该never block on async code。这可以通过使用ConfigureAwait(false) 来解决,它告诉TaskAwaitable 不要将延续封送回并简单地在调用它的当前线程上执行:

public static async Task<String> getResponse(String url)
{
    HttpClient httpClient = new HttpClient();
    HttpResponseMessage request = await httpClient.GetAsync(url).ConfigureAwait(false);
    String stream = await request.Content.ReadAsStringAsync().ConfigureAwait(false);
    return stream;
}

另一个更好的IMO解决方案是正确使用async方法和await,而不是阻止:

string response = await UtilityClass.getResponse(requestUrl)

这需要您将async 关键字添加到调用方法中。如果你不能,也许同步 http 请求可能是更好的解决方案。

编辑

引用@EricLippert 的评论使这更容易理解:

这里要理解的关键是result = task.Result;意味着在结果可用之前什么都不做,而result = await task;表示做其他事情直到结果可用。两者都将Task&lt;string&gt; 转换为字符串,但一个阻止另一个不阻止

有很多很好的帖子解释了 async/await 的基本原理:

  1. Asynchronous Programming with Async and Await
  2. Asynchrony in C# 5 Series (Eric Lippert)
  3. Async Await Intro (Stephan Cleary)
  4. Async Await FAQ

【讨论】:

  • 我添加的“.Result”是从方法getResponse获取字符串结果,因为它返回一个Task,我想获取String..对不起,也许我有点有点困惑。我没有找到同步http请求的例子:/只有异步......
  • 当您调用TaskResult 属性时,它会像您使用同步请求时那样阻塞。添加ConfigureAwait(false),如我在示例中所示
  • 是的,谢谢,我添加了 ConfigureAwait(false) 并且代码可以正常工作,但是我如何在没有 .Result 的情况下获得响应流?我调用它工作的 getResponse 方法并返回 Task,我怎样才能从这个返回的任务中获取 String?
  • 如果您是await getResponse,那么该字符串将从Task 为您解开。如果没有,请使用 Result 属性(由于您使用了 ConfigureAwait,它将阻塞但不会死锁)
  • @Pame1692:这里要理解的关键是result = task.Result; 表示在结果可用之前什么都不做result = await task; 表示做其他事情直到结果出来。两者都将Task&lt;string&gt; 转换为string,但一个阻止另一个不阻止。
最近更新 更多