C# HttpRequestMessage.Content在ASP.NETWebAPI中的日志删除句柄中读取时丢失
当尝试在控制器中的操作中删除对象时,它偶尔看起来是空的。我发现这是由于C# HttpRequestMessage.Content在ASP.NETWebAPI中的日志删除句柄中读取时丢失,c#,web-services,rest,asp.net-web-api,C#,Web Services,Rest,Asp.net Web Api,当尝试在控制器中的操作中删除对象时,它偶尔看起来是空的。我发现这是由于SendAsync()中的ReadAsStringAsync()重写了DelegatingHandler。问题在于内容。当我的客户端发送一个内容体并在记录器中读取时,控制器操作调用程序永远不会读取它(或者可能在JsonFormatter中的某个地方)。我怀疑对Content.ReadAsStringAsync()的后续调用不会引发异常,但也不会返回预期的内容正文(返回的某些信息表明异步读取已完成) 但是我的问题仍然存在,因为我
SendAsync()
中的ReadAsStringAsync()
重写了DelegatingHandler
。问题在于内容。当我的客户端发送一个内容体并在记录器中读取时,控制器操作调用程序永远不会读取它(或者可能在JsonFormatter
中的某个地方)。我怀疑对Content.ReadAsStringAsync()
的后续调用不会引发异常,但也不会返回预期的内容正文(返回的某些信息表明异步读取已完成)
但是我的问题仍然存在,因为我想在操作中读取[FromBody]
参数,当Content.ReadStringAsync
的条件被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;
});
}
}
公共类日志处理程序:DelegatingHandler
{
受保护的覆盖任务SendAsync(HttpRequestMessage请求,CancellationToken CancellationToken)
{
var apiRequest=new-WebApiUsageRequest(请求);
书面记录(APIELOG);
request.Content.ReadAsStringAsync().ContinueWith(t=>
{
aprequest.Content=t.Result;
书面记录(APIELOG);
});
返回base.sendaync(请求,取消令牌).ContinueWith(任务=>
{
var apiResponse=新的WebApiUsageResponse(task.Result);
apiResponse.Content=task.Result.Content!=null?task.Result.Content.ReadAsStringAsync()。结果:null;
写日志(apiResponse);
返回任务。结果;
});
}
}
有人知道这个问题的解决办法吗?这是故意的。在ASP.NET Web API中,正文内容被视为只能读取一次的仅向前的流
您可以尝试使用ASP.NET Web API跟踪,但我尚未使用POST请求对其进行测试,因此我不确定它是如何/是否跟踪请求正文的(它正在跟踪GET请求的参数)。您可以在此处阅读更多内容:
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
。
.
.ReadAsStreamAsync方法返回正文内容
var body = string.Empty;
using (var reader = new StreamReader(request.Content.ReadAsStreamAsync().Result))
{
reader.BaseStream.Seek(0, SeekOrigin.Begin);
body = reader.ReadToEnd();
}
这对我很有用:
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表示,因此我可以将其用于异常处理和日志记录
找到公认的答案以下是我最后做的:
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关于使用“using”块的回答对我不起作用,因为在释放读卡器时,底层流也被关闭。忘了提到这是RC。我怀疑RTM牙床的观察结果仍然相同。我认为对于我的要求,我可以接受不将内容写入日志。然而,对于所有试图记录内容并在POST Actions软件中使用[FromBody]的web api开发人员来说,这应该是一个“需要注意的要点”,即使用块将关闭底层steam。但在这里,我们无法接收请求头这不是同一回事。您阅读的是请求内容,而不是响应内容,这也是它工作的原因