将`HttpClient.SendAsync`从异步改为同步。

huangapple go评论128阅读模式
英文:

Convert async to sync for HttpClient.SendAsync

问题

我想要像这样使用REST调用:

private async Task<HttpResponseMessage> SendRequestHelperAsync(HttpRequestMessage message, CancellationToken ct)
{
    var response = await HttpClient.SendAsync(message, ct).ConfigureAwait(false);
    return response;
}

从非异步方法中使用它时,它会被阻塞。当我这样使用它时:

var response = SendRequestHelperAsync(message, ct).Result;

它会被阻塞。当我直接使用它时,它也会被阻塞:

HttpResponseMessage response = HttpClient.SendAsync(message, ct).Result;

当我寻找解决方案时,我遇到了使用任务的方法,像这样:

var task = Task.Run(async () => { await SendRequestHelperAsync(message, ct); });

但是,我该如何获取结果呢?

(我正在从.NET Framework 4.8的WinForms应用程序中使用它。)

英文:

I want to use a REST-call like this:

private async Task&lt;HttpResponseMessage&gt; SendRequestHelperAsync(HttpRequestMessage message, CancellationToken ct)
        {
            var response = await HttpClient.SendAsync(message, ct).ConfigureAwait(false);
            return response;
        }

from a non-async method. When I use it like this:

var response = SendRequestHelperAsync(message, ct).Result;

it gets stuck. When I use it directly, it gets stuck as well:

HttpResponseMessage response = HttpClient.SendAsync(message, ct).Result;

When I was looking for some solution, I came across using a task like this:

var task = Task.Run(async () =&gt; { await SendRequestHelperAsync(message, ct); });

but then how do I get the result back?

(I am using it from .Net Framework 4.8, WinForms Application.)

答案1

得分: 1

我想要在一个非异步的方法中使用[异步代码]。

最好的答案是"不要"。相反,走一路异步

可以使用Task.Run作为解决方法;这是线程池的技巧,在这种特定情况下会起作用(警告:它并不在每种情况下都适用,特别是,如果Task.Run委托中的代码访问UI元素,那么这个技巧将不会起作用)。线程池的技巧支持返回类型,如下所示:

var response = Task.Run(async () => await SendRequestHelperAsync(message, ct))
    .GetAwaiter().GetResult();

然而,最好的答案仍然是"不要"。您死锁(在我的博客中详细解释)的事实意味着这段代码正在UI线程上运行,并且解决方案试图在网络请求上阻塞UI线程。阻塞UI线程会给用户带来不好的体验。

相反,最好的解决方案是重新设计UI,以便不需要阻塞。通常的做法是添加某种旋转器或"加载中..."UI元素,然后在异步操作完成时更新UI。

英文:

> I want to use [async code] from a non-async method.

The best answer is "don't". Instead, go async all the way.

You could use Task.Run as a workaround; this is the thread pool hack, which will work in this specific case (warning: it does not work in every case, specifically, if the code in the Task.Run delegate accesses UI elements, then this hack will not work). The thread pool hack supports return types, as such:

var response = Task.Run(async () =&gt; await SendRequestHelperAsync(message, ct))
    .GetAwaiter().GetResult();

However, the best answer is still "don't". The fact that you're deadlocking (as explained in detail on my blog) implies that this code is being run on the UI thread, and the solution is attempting to block the UI thread on a network request. Blocking the UI thread is a poor user experience.

Instead, the best solution is to redesign the UI so that no blocking is necessary. This is usually done by adding some kind of spinner or "loading..." UI element, and then updating the UI when the asynchronous operation completes.

huangapple
  • 本文由 发表于 2023年2月8日 23:54:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/75388372.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定