我应该在DelegatingHandler中的ReadAsAsync之后使用ContinueWith()

时间:2013-04-04 17:16:30

标签: asp.net-web-api

假设我有一个DelegatingHandler用于记录api请求。我想访问请求并可能响应内容以保存到数据库。

我可以直接使用:

访问
var requestBody = request.Content.ReadAsStringAsync().Result;

我在很多例子中看到了这一点。也建议有人使用它here看似知道他们在说什么。顺便提一下,之所以提出这样的建议,是因为海报最初使用的是ContinueWith,但却出现了间歇性的问题。

在其他地方,here,作者明确表示不要这样做,因为它可能导致死锁并建议使用ContinueWith。这些信息显然直接来自ASP.net团队。

所以我有点困惑。这两个场景在我看来非常相似,所以看起来很矛盾。

我应该使用哪个?

2 个答案:

答案 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