繁体   English   中英

为什么HTTP请求永远不会在异步等待状态下返回?

[英]Why do HTTP requests never return with async await?

我正在尝试从在IIS 8.5上运行的ASP.NET应用程序内对另一个服务器进行HTTP调用。

首先,我从Microsoft的文章“ 从.NET客户端(C#)调用Web API”中获取了一些提示。 我可以很容易地看到它们在此处进行HTTP调用的方式。 仅显示一个简化的示例:

    static async Task<Product> GetProductAsync(string path)
    {
        HttpResponseMessage response = await client.GetAsync(path);
        if (response.IsSuccessStatusCode)
        {
            // retrieve response payload
            ... = await response.Content.ReadAsAsync<...>();
        }
        // do something with data
    }

我想这很容易,所以我很快为我的应用程序编写了一个类似的方法(请注意, ReadAsAsync扩展方法似乎需要一个附加的库 ,因此我选择了一种内置的,更抽象的方法,但推测是类似的方法):

    private async Task<MyInfo> RetrieveMyInfoAsync(String url)
    {
        var response = await HttpClient.GetAsync(url);

        response.EnsureSuccessStatusCode();
        var responseBody = await response.Content.ReadAsStringAsync();

        return JsonConvert.DeserializeObject<MyInfo>(responseBody);
    }

不幸的是,调用此方法将导致我的应用程序挂起。 调试时,事实证明,对GetAsyncawait调用永远不会返回。

在四处搜寻之后,我偶然发现了一个遥远相似的问题 ,在其评论部分中,我发现 B先生的 一个非常有趣的建议

删除所有异步内容,并确保其有效。

因此,我尝试了一下:

    private Task<MyInfo> RetrieveMyInfoAsync(String url)
    {
        return HttpClient.GetAsync(url).ContinueWith(response =>
        {
            response.Result.EnsureSuccessStatusCode();
            return response.Result.Content.ReadAsStringAsync();
        }).ContinueWith(str => JsonConvert.DeserializeObject<MyInfo>(str.Result.Result));
    }

(对我而言)有些令人惊讶,它有效。 GetAsync在不到一秒钟的时间内从其他服务器返回了预期的响应。

现在,同时使用AngularJS,我对诸如response.Result.Contentstr.Result.Result类的东西感到有些失望。 在AngularJS中,我希望上面的调用就像这样:

$http.get(url).then(function (response) {
    return response.data;
});

即使我们不赞成JavaScript中发生的自动JSON反序列化,但AngularJS代码仍然更容易,例如, response未包装在promise中或类似的内容,我也不会得到Task<Task<...>>这样的结构Task<Task<...>>从延续函数中返回另一个诺言时。

因此,如果后者可以正常工作的话,我对使用ContinuesWith语法而不是更具可读性的async-await模式并不满意。

我的C#HTTP调用的async-await变体在做什么?

因此,从ConfigureAwait(false)帮助解决您的问题这一事实来看,请阅读Stephen Cleary的博客中的内容: http : //blog.stephencleary.com/2012/07/dont-block-on-async-code.html

这个家伙几乎是一个async专家(他写了《 C#Cookbook中的并发性》一书),所以我能说的他可能解释得更好。 基本上,您是在某个地方阻塞ASP.NET线程,也许不是一直使用await而是而是WaitResultGetResult() 您应该可以使用该博客自己诊断问题。

ConfigureAwait(false)作用是不会捕获当前上下文,因此HTTP请求在ASP.NET上下文以外的其他位置(正确)执行,从而避免了死锁。

编辑:

根据您的评论判断, GetAwaiter().GetResult()是导致此问题的原因。 如果将其更改为await ,并将调用方法更改为async ,则可能会修复所有问题。

由于C#7.0和async Task Main()方法都支持,所以实际上没有理由阻塞而不是在应用程序代码中使用await

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM