同步使用HttpClient的“正确方法”是什么?

时间:2018-11-28 22:29:41

标签: c# asynchronous async-await

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

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

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

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

我实际上 did 试图在调用链上传播异步行为,但是后来我发现自己有50个文件有很深的变化,仍然有数百个编译器错误需要解决,并失去了希望。我被击败了。

然后,回到问题所在,考虑到微软的建议,从不使用WebRequest进行新开发,而改用HttpClient(仅提供异步API),我该怎么办?

这是我在做什么的伪代码...

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
}

但是,我被告知,由于同步上下文,从ASP.NET之类的方法中调用.Result可能会导致死锁。

猜怎么着,该批处理过程将从ASP.NET控制器开始。是的,再次,我知道,这很愚蠢。从ASP.NET运行时,它仅是“批处理”一项,而不是整个批处理,但是我离题了,仍然从ASP.NET调用它,因此我担心死锁。

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

3 个答案:

答案 0 :(得分:14)

对于现在遇到此问题的任何人,.NET 5.0 已将同步 Send 方法添加到 HttpClienthttps://github.com/dotnet/runtime/pull/34948

因此您可以使用它代替 SendAsync。例如

public string GetValue()
{
    var client = new HttpClient();
            
    var webRequest = new HttpRequestMessage(HttpMethod.Post, "http://your-api.com")
    {
        Content = new StringContent("{ 'some': 'value' }", Encoding.UTF8, "application/json")
    };

    var response = client.Send(webRequest);

    using var reader = new StreamReader(response.Content.ReadAsStream());
            
    return reader.ReadToEnd();
}

此代码只是一个简化示例,尚未准备好用于生产。

答案 1 :(得分:3)

尝试关注-

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

仅在无法使用异步方法时才使用它。

此方法完全无死锁,如msdn博客上所述- https://blogs.msdn.microsoft.com/jpsanders/2017/08/28/asp-net-do-not-use-task-result-in-main-context/

答案 2 :(得分:1)

您也可以看看使用Nito.AsyncEx,它是一个nuget程序包。我听说过使用Task.Run()的问题,这个可以解决这个问题。这是api文档的链接: http://dotnetapis.com/pkg/Nito.AsyncEx/4.0.1/net45/doc/Nito.AsyncEx.AsyncContext

这是在控制台应用程序中使用异步方法的示例: https://blog.stephencleary.com/2012/02/async-console-programs.html