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

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

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

这是我的DelegatingHandler代码:

 public class LogHandler : DelegatingHandler { protected override Task 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; }); } } 

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

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

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

  • 跟踪ASP.NET Web API(Ron Cain)
  • ASP.NET Web API跟踪预览(Ron Cain)
  • 跟踪ASP.NET Web API(Mike Wasson)

ReadAsStreamAsync方法返回正文内容。

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

但如果你在SendAsync中使用下面的代码,它可以正常工作

  if (request.Content != null) { request.Content.ReadAsByteArrayAsync().ContinueWith ( (task) => { var xxx = System.Text.UTF8Encoding.UTF8.GetString(task.Result); }); } return base.SendAsync(request, cancellationToken) //than call the base 

。 。 。

这对我有用:

 using (var stream = new MemoryStream()) { var context = (HttpContextBase)Request.Properties["MS_HttpContext"]; context.Request.InputStream.Seek(0, SeekOrigin.Begin); context.Request.InputStream.CopyTo(stream); string requestBody = Encoding.UTF8.GetString(stream.ToArray()); } 

为我返回参数对象的json表示,因此我可以将它用于exception处理和日志记录。

在这里找到接受的答案

这是我最终做的事情:

 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; } 

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