假设我有一个DelegatingHandler用于记录api请求。我想访问请求并可能响应内容以保存到数据库。
我可以直接使用:
访问var requestBody = request.Content.ReadAsStringAsync().Result;
我在很多例子中看到了这一点。也建议有人使用它here看似知道他们在说什么。顺便提一下,之所以提出这样的建议,是因为海报最初使用的是ContinueWith,但却出现了间歇性的问题。
在其他地方,here,作者明确表示不要这样做,因为它可能导致死锁并建议使用ContinueWith。这些信息显然直接来自ASP.net团队。
所以我有点困惑。这两个场景在我看来非常相似,所以看起来很矛盾。
我应该使用哪个?
答案 0 :(得分:3)
您应该使用await
。
Result
的一个问题是it can cause deadlocks,正如我在博客中描述的那样。
ConfigureAwait
的问题是默认情况下它将在HTTP请求上下文之外的线程池上执行延续。
您可以使用这些方法中的任何一种获得工作解决方案(尽管Youssef指出,Result
仍将具有次优性能),但为什么还要烦恼? await
为您完成所有工作:没有死锁,最佳线程以及在HTTP请求上下文中恢复。
var requestBody = await request.Content.ReadAsStringAsync();
编辑.NET 4.0:首先,我强烈建议升级到.NET 4.5。 .NET 4.5中增强了ASP.NET运行时,以正确处理基于Task
的{{1}}操作。因此,如果将WebAPI安装到.NET 4.0项目中,则下面的代码可能有效,也可能无效。
也就是说,如果您想使用旧学校async
正确 ,那么这样的事情应该有效:
ContinueWith
现在很清楚为什么protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
var context = TaskScheduler.FromCurrentSynchronizationContext();
var tcs = new TaskCompletionSource<HttpResponseMessage>();
HttpResponseMessage ret;
try
{
... // logic before you need the context
}
catch (Exception ex)
{
tcs.TrySetException(ex);
return tcs.Task;
}
request.Content.ReadAsStringAsync().ContinueWith(t =>
{
if (t.Exception != null)
{
tcs.TrySetException(t.Exception.InnerException);
return;
}
var content = t.Result;
try
{
... // logic after you have the context
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
tcs.TrySetResult(ret);
}, context);
return tcs.Task;
}
会好得多......
答案 1 :(得分:1)
调用.Result会同步阻塞线程,直到任务完成。这不是一件好事,因为线程正在旋转,等待异步操作完成。
如果你使用的是.NET 4.5,你应该更喜欢使用ContinueWith,甚至更好,async和等待。这是一个很好的资源,您可以从中了解更多信息:
http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx