死锁从webapi中的异步DelegatingHandler读取异步响应内容

问题

我在WebAPI中使用DelegatingHandler来读取响应内容并将其审核到数据库。

当代码到达.ReadAsStringAsync()时,它似乎锁定并阻止其他请求完成。 我只知道这一点,因为当我删除违规行时,它完美无缺。

public static void Register(HttpConfiguration config) { config.MessageHandlers.Add(new ResourceAuditHandler()); } public class ResourceAuditHandler : DelegatingHandler { protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var response = await base.SendAsync(request, cancellationToken); string content = ""; if (response.Content != null) { //THIS SEEMS TO CREATE DEADLOCK! content = await response.Content.ReadAsStringAsync(); } AuditResponseToDatabase(content); return response; } } 

可能的原因

我已经读过,当应用程序的两个位试图从同一个请求/响应(DelegatingHandler和Controller / ModelBinder)读取内容时会发生这种情况……或者更具体地说,当一个人尝试读取异步响应的.Result时,但另一个实例已经读取了结果/响应流,然后为空。

我的第一个请求,命中一个简单的控制器,但第二个请求,命中一个控制器,其属性检查Action参数“id”以检查它是否为null。 我已经读过,当DelegatingHandler和控制器ModelBinder都试图从响应中读取时,你会遇到死锁。

替代方法 (也失败)

我也尝试使用其他方法(如其他SO问题所示),它使用.ReadAsByteArrayAsync(),但这似乎仍然锁定。 我知道这个方法不使用.Result方法并直接从响应流中读取它(不知何故)。

  var response = await base.SendAsync(request, cancellationToken); string content= ""; if (response.Content != null) { var bytes = await response.Content.ReadAsByteArrayAsync(); responseContent = Encoding.UTF8.GetString(bytes); } AuditResponseToDatabase(content); 

请帮忙!

彼得,首先,你对这个僵局的原因是正确的。 尝试一直使用async/await 。 换句话说,不要阻止async代码。 你应该做的另一件事是使用.ConfigureAwait(false)

  var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false); string content = ""; if (response.Content != null) { content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); } 

您可以在此链接找到更多信息

如果以上都没有,请提供完整的示例,好吗?

希望这可以帮助!