首页 > 解决方案 > 同步使用 HttpClient 的“正确方法”是什么?

问题描述

我在“正确方式”周围使用了引号,因为我已经很清楚使用异步 API 的正确方式是让异步行为在整个调用链中传播。这不是一个选择。

我正在处理一个非常庞大且复杂的系统,该系统专门设计用于在循环中同步进行批处理。

我突然使用 HttpClient 的原因是因为之前批处理的所有数据都是从 SQL 数据库中收集的,现在我们正在添加一个 Web API 调用。

是的,我们在同步执行的循环中调用 Web API。我知道。将整个事情重写为异步只是不是一种选择。这实际上是我们想要做的。(我们尽可能减少 API 调用的数量)

实际上,我确实尝试将异步行为传播到调用链上,但后来我发现自己有 50 个文件深度变化,仍然有数百个编译器错误需要解决,并且失去了所有希望。我被打败了。

那么,回到这个问题,鉴于微软建议不要将 WebRequest 用于新开发,而是使用仅提供异步 API 的 HttpClient,我该怎么办?

这是我正在做的一些伪代码......

foreach (var thingToProcess in thingsToProcess)
{
    thingToProcess.ProcessStuff(); // This makes an API call
}

如何实现 ProcessStuff()?

我的第一个实现看起来像这样

public void ProcessStuff()
{
    var apiResponse = myHttpClient // this is an instance of HttpClient
        .GetAsync(someUrl)
        .Result;

    // do some stuff with the apiResponse
}

但是有人告诉我,由于同步上下文,以这种方式调用 .Result 会导致死锁。

猜猜看,这个批处理将从 ASP.NET 控制器启动。是的,我知道,这很愚蠢。当它从 ASP.NET 运行时,它只是“批处理”一个项目而不是整个批次,但我离题了,它仍然从 ASP.NET 调用,因此我担心死锁。

那么处理这个问题的“正确方法”是什么?

标签: c#asynchronousasync-await

解决方案


尝试以下操作:

var task = Task.Run(() => myHttpClient.GetAsync(someUrl)); 
task.Wait();
var response = task.Result;

仅当您无法使用async方法时才使用它。

如 MSDN 博客中所述,此方法完全无死锁: ASP.Net–Do not use Task .Result in main context


推荐阅读