假设我有一个 DelegatingHandler 用于记录 api 请求。我想访问请求和响应内容以保存到数据库。
我可以直接使用:
var requestBody = request.Content.ReadAsStringAsync().Result;
我在很多例子中都看到了这一点。还建议似乎知道他们在说什么的人使用 here 。顺便提一下,提出这个建议是因为海报最初使用 ContinueWith 但出现了间歇性问题。
在其他地方, here ,作者明确表示不要这样做,因为它会导致死锁,并建议使用 ContinueWith 代替。此信息显然直接来自 ASP.net 团队。
所以我有点困惑。这两种情况在我看来非常相似,因此似乎是相互矛盾的。
我应该使用哪个?
最佳答案
您应该使用 await
。Result
的问题之一是 it can cause deadlocks ,正如我在我的博客上所描述的。ConfigureAwait
的问题在于,默认情况下,它将在 HTTP 请求上下文之外的线程池上执行延续。
您可以使用这两种方法中的任何一种来获得有效的解决方案(尽管正如 Youssef 指出的那样,Result
仍将具有次优性能),但何必呢? await
为您完成这一切:没有死锁、最佳线程以及在 HTTP 请求上下文中恢复。
var requestBody = await request.Content.ReadAsStringAsync();
.NET 4.0 编辑: 首先,我强烈建议升级到 .NET 4.5。 ASP.NET 运行时在 .NET 4.5 中得到了增强,可以正确处理基于
Task
的 async
操作。因此,如果您将 WebAPI 安装到 .NET 4.0 项目中,下面的代码可能会也可能不会起作用。也就是说,如果您想尝试正确使用老式
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;
}
现在很清楚为什么
await
好多了......关于asp.net-web-api - 我应该在 DelegatingHandler 中的 ReadAsAsync 之后使用 ContinueWith(),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15817594/