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

时间:2014-06-20 11:16:30

标签: c# async-await httphandler dotnet-httpclient

问题

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

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

public static void Register(HttpConfiguration config)
{
    config.MessageHandlers.Add(new ResourceAuditHandler());
}

public class ResourceAuditHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> 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”以检查它是否为空。我已经读过,当DelegatingHandler和控制器ModelBinder都试图从响应中读取时,你会遇到死锁。

替代方法(也失败)

我也尝试过使用 .ReadAsByteArrayAsync()的其他方法(如其他SO问题所示),但这似乎仍然锁定。我知道这种方法不使用 .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);

请帮忙!

1 个答案:

答案 0 :(得分:1)

彼得,首先,你对这个僵局的原因是正确的。尽量一直使用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); 
    }

您可以在此link

找到更多信息

如果以上都不奏效,请提供完整的示例,好吗?

希望这有帮助!