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.
我有同样的问题,这个答案为我解决了。
简而言之,您必须使用ConfigureAwait(false)扩展名来避免死锁:
var response = await client.PostAsJsonAsync(useUrl, o).ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)
您为什么不遵循异步等待模式是有原因的吗?您正在调用异步方法,但不等待它。如果代码中调用您的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)
System.Net.ServicePointManager.Expect100Continue = false;
Run Code Online (Sandbox Code Playgroud)
在我们的例子中,一行代码解决了这个问题。来自不同团队的开发人员提出了该建议,并且该建议有效。我还没有用谷歌搜索它并阅读足够多的内容来解释它所解决的问题。