HttpClient.PostAsJsonAsync永远不会看到帖子成功和响应的时间

Dan*_*nny 11 c# connection-timeout async-await dotnet-httpclient

我们正在使用HttpClient将json发布到一个宁静的Web服务.在一个例子中,我们遇到了困扰我们的事情.使用postman,fiddler等工具,我们可以发布到端点并看到它正在工作.当我们对HttpClient.PostAsJsonAsync做同样的事情时,我们可以在我们发布的软件中验证它收到的数据就好了.但是,我们的PostAsJsonAsync总是最终超时,而不是给我们一个响应.

我们与创建我们正在消费的服务的团队合作,加上我们的额外测试,我们还没有真正超时的服务.

每次我们使用HttpClient发布帖子时,我们都可以验证我们发布的目标软件是否确实获得了数据.每当我们从任何其他工具发布到目标软件的帖子时,我们总是很快看到状态代码为200的响应.关于HttpClient的某些内容未能接受来自此特定服务的响应.有没有人知道我们可以从这里看到什么?

这是代码(虽然它是如此千篇一律,我几乎觉得不需要)

public string PostData(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
    {
        using (var client = new HttpClient())
        {
            if (timeoutMinutes > 0)
            {
                client.Timeout = new TimeSpan(0,timeoutMinutes,0);
            }
            var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
            var response = client.PostAsJsonAsync(useUrl, o).Result;
            if(response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                return response.Content.ReadAsStringAsync().Result;
            }
            return "";
        }

    }
Run Code Online (Sandbox Code Playgroud)

Yuv*_*kov 10

这个:

var response = client.PostAsJsonAsync(useUrl, o).Result;
Run Code Online (Sandbox Code Playgroud)

导致代码死锁.在阻止异步API的情况下通常会出现这种情况,这就是为什么你会遇到"我看不到任何响应"的原因.

这怎么会造成僵局?您在包含同步上下文的环境中执行此请求的事实,可能是属于UI的同步上下文.它正在执行异步请求,当响应到达时,它会继续通过IO完成线程,该线程尝试将延续发布到同一UI上下文中,该上下文当前被您的.Result调用阻止.

如果要同步发出HTTP请求,请WebClient改用.如果要正确利用异步API,请使用await而不是阻止.Result.


web*_*uff 6

我有同样的问题,这个答案为我解决了。

简而言之,您必须使用ConfigureAwait(false)扩展名来避免死锁:

var response = await client.PostAsJsonAsync(useUrl, o).ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)


Jus*_*son 5

您为什么不遵循异步等待模式是有原因的吗?您正在调用异步方法,但不等待它。如果代码中调用您的REST服务是一个Windows窗体或ASP.NET应用程序,但你没有说.Result可能造成你的问题

您可以这样重组您的方法:

public async Task<string> PostData(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
{
    using (var client = new HttpClient())
    {
        if (timeoutMinutes > 0)
        {
            client.Timeout = new TimeSpan(0,timeoutMinutes,0);
        }
        var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
        var response = await client.PostAsJsonAsync(useUrl, o);
        if(response.StatusCode == System.Net.HttpStatusCode.OK)
        {
            return await response.Content.ReadAsStringAsync();
        }
        return "";
    }

}
Run Code Online (Sandbox Code Playgroud)


Dan*_*nny 1

System.Net.ServicePointManager.Expect100Continue = false;
Run Code Online (Sandbox Code Playgroud)

在我们的例子中,一行代码解决了这个问题。来自不同团队的开发人员提出了该建议,并且该建议有效。我还没有用谷歌搜索它并阅读足够多的内容来解释它所解决的问题。