带有返回内容的 Task<string> 的 C# httpclient
Posted
技术标签:
【中文标题】带有返回内容的 Task<string> 的 C# httpclient【英文标题】:C# httpclient with Task<string> that return content 【发布时间】:2018-01-08 14:07:47 【问题描述】:我有以下功能,但无法调试它,因为响应永远不会到来。另一边的服务正在工作。任何帮助都会受到重视,我无法推断出必须如何处理 SO 中的其他答案
public async Task<string> PostObjectToWebServiceAsJSON(object objectToPost, string validatorName, string method)
using (var client = new HttpClient())
client.BaseAddress = new Uri("myuri" + "/" + method);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP POST
var response = await client.PostAsJsonAsync("", objectToPost);
if (response.IsSuccessStatusCode)
return await response.Content.ReadAsStringAsync();
else
string errplugin = "Error";
return null;
我是这样称呼它的:
public PaymentResponseInternal Post(some stuff here)
Task<string> retornoPluginAsync = PostObjectToWebServiceAsJSON(some stuff here);
retornoPluginAsync.Wait();
string result = retornoPluginAsync.Result;
return JsonConvert.DeserializeObject<PaymentResponseInternal>(result);
【问题讨论】:
当您说“响应永远不会到来”时,您是什么意思?是挂了吗?你怎么调用这个函数?这很可能是一个僵局。 是的,这是一个死锁,因为您正在调用retornoPluginAsync.Result
。你需要await
那个电话。见这里:blog.stephencleary.com/2012/07/dont-block-on-async-code.html
听起来public PaymentResponseInternal Post(some stuff here)
应该是public async Task<PaymentResponseInternal> Post(some stuff here)
并且应该在内部使用await
。
你也在等待那个函数。异步代码就像一个病毒,一旦你开始,它会慢慢消耗你的整个项目(这是一件好事)
然后看看this,不幸的是,只有你才能知道哪种方法最适合解决你的问题。
【参考方案1】:
如 cmets 中所述,您应该将 PaymentResponseInternal
设为一个返回 Task<PaymentResponseInternal>
的 async
方法并等待它。
您不应该混合使用同步和异步代码。造成这种情况的原因之一是您可能会出现死锁,正如您在此处发现的那样。更多信息请参考@Stephen Cleary 的文章:https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
如果由于某种原因您无法将Post
方法设为async
,您可以尝试不捕获PostObjectToWebServiceAsJSON
方法中的上下文,方法是在每个ConfigureAwait(false)
之后调用ConfigureAwait(false)
:
public async Task<string> PostObjectToWebServiceAsJSON(object objectToPost, string validatorName, string method)
using (var client = new HttpClient())
client.BaseAddress = new Uri("myuri" + "/" + method);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.PostAsJsonAsync("", objectToPost).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
else
return null;
请参阅@Stephen Cleary 的博文以了解相关信息:https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
【讨论】:
【参考方案2】:随着您对问题的更新,您在同步调用PostObjectToWebServiceAsJSON
时遇到了死锁情况。您应该在 Wait()
之前添加对 retornoPluginAsync.ConfigureAwait(false);
的调用。 ConfigureAwait(false)
将 Task
配置为不需要原始调用上下文,并且在您的情况下应该解决死锁。
public PaymentResponseInternal Post(some stuff here)
Task<string> retornoPluginAsync = PostObjectToWebServiceAsJSON(some stuff here);
retornoPluginAsync.ConfigureAwait(false); // Add this
retornoPluginAsync.Wait();
string result = retornoPluginAsync.Result;
return JsonConvert.DeserializeObject<PaymentResponseInternal>(result);
【讨论】:
我这样做,编译但不返回任何东西。 其实我很怀念问题中的等待 看起来问题中的代码是一个移动目标,正在使发布的回复无效...... 这个答案显然永远不会起作用,因为 OP 肯定有编译过的代码。 是的,对不起,大卫,我的错误,我删除了等待尝试的东西,但忘记再写一遍以上是关于带有返回内容的 Task<string> 的 C# httpclient的主要内容,如果未能解决你的问题,请参考以下文章
使用 async/await 并从 ASP.NET Web API 方法返回 Task<HttpResponseMessage>