在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使用“使用”块的答案对我不起作用,因为当阅读器被处理时,底层流也被关闭。
- 无法添加对’System.Net.Http’的引用。 请确保它在全局程序集缓存中
- ModelBindervalidation使用reflection在getter上中断
- 序列化为JSON,尽管指定了NullValueHandling,但使用Json.NET和Web API省略了Nullable Date
- 如何使用自定义属性扩展IdentityUser
- 如何更改默认的ASP.NET MVC Web API媒体格式化程序?
- 如何在ASP.NET Web API中执行异步“即发即忘”操作
- .NET WebAPI集中授权
- REST服务身份validation
- JSON.NET反序列化属性名称转换为具有自定义ContractResolver的ExpandoObject