在ASP.Net Web API中的日志记录DelegatingHandler中读取HttpRequestMessage.Content时丢失

San*_*ndo 14 c# rest web-services asp.net-web-api

在Controller中的Action中尝试对象时,偶尔似乎是null.我发现,这是由于ReadAsStringAsync()SendAsync()的覆盖DelegatingHandler.问题在于内容.当我的客户端发送一个内容正文并在记录器中读取它时,它永远不会被Controller Action Invoker读取(或者可能在某个地方JsonFormatter).我怀疑后续调用Content.ReadAsStringAsync()不会抛出异常,但也不会返回预期的内容体(返回一些信息表明异步读取已完成).

但是我的问题仍然存在,因为我想[FromBody]在一个动作中读取一个参数,当它Content.ReadStringAsync获得RaceCondition的时候它是null DelegatingHandler.当JsonFormatter虽然赢了,我得到的对象,但是这是罕见的(只在服务启动).

这是我的DelegatingHandler代码:

public class LogHandler : DelegatingHandler
{

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var apiRequest = new WebApiUsageRequest(request);
        WriteLog(apiRequest);
        request.Content.ReadAsStringAsync().ContinueWith(t =>
        {
            apiRequest.Content = t.Result;
            WriteLog(apiRequest);
        });

        return base.SendAsync(request, cancellationToken).ContinueWith(task =>
        {
            var apiResponse = new WebApiUsageResponse(task.Result);
            apiResponse.Content = task.Result.Content != null ? task.Result.Content.ReadAsStringAsync().Result : null;
            WriteLog(apiResponse);
            return task.Result;
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有人有解决这个问题的线索?

tpe*_*zek 9

这是设计的.在ASP.NET Web API中,正文内容被视为只能读取一次的仅向前流.

您可能尝试使用ASP.NET Web API跟踪,但我还没有使用POST请求进行测试,所以我不确定它是如何跟踪请求正文(它确实是跟踪GET请求的参数).你可以在这里阅读更多:

  • 谢谢.我认为,根据我的要求,我可以忍受不将内容写入日志.然而,对于所有尝试记录内容的web api开发人员以及在POST Actions中使用[FromBody],这应该是一个"注意事项" (2认同)

pir*_*glu 7

ReadAsStreamAsync方法返回正文内容.

var body = string.Empty;
using (var reader = new StreamReader(request.Content.ReadAsStreamAsync().Result))
{
    reader.BaseStream.Seek(0, SeekOrigin.Begin);
    body = reader.ReadToEnd();
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,using块将关闭底层蒸汽。 (2认同)

iva*_*lle 5

这是我最终做的:

public string SafelyReadContent(HttpRequestMessage request)
{
    var stream = request.Content.ReadAsStreamAsync().Result;
    var reader = new StreamReader(stream);
    var result = reader.ReadToEnd();
    stream.Seek(0, SeekOrigin.Begin);

    return result;
}
Run Code Online (Sandbox Code Playgroud)

@pirimoglu 使用“using”块的答案对我不起作用,因为当读取器被释放时,底层流也被关闭。