请求/响应记录的响应正文

我正在尝试编写一个Owin midleware组件,它将记录每个传入的请求和对数据库的响应。

这是我设法得到多远。

我被困在阅读回复。 说:

Stream不支持阅读。

我如何阅读Response.Body?

public class LoggingMiddleware : OwinMiddleware { private static Logger log = LogManager.GetLogger("WebApi"); public LoggingMiddleware(OwinMiddleware next, IAppBuilder app) : base(next) { } public override async Task Invoke(IOwinContext context) { using (var db = new HermesEntities()) { var sw = new Stopwatch(); sw.Start(); var logRequest = new log_Request { Body = new StreamReader(context.Request.Body).ReadToEndAsync().Result, Headers = Json.Encode(context.Request.Headers), IPTo = context.Request.LocalIpAddress, IpFrom = context.Request.RemoteIpAddress, Method = context.Request.Method, Service = "Api", Uri = context.Request.Uri.ToString(), UserName = context.Request.User.Identity.Name }; db.log_Request.Add(logRequest); context.Request.Body.Position = 0; await Next.Invoke(context); var mem2 = new MemoryStream(); await context.Response.Body.CopyToAsync(mem2); var logResponse = new log_Response { Headers = Json.Encode(context.Response.Headers), Body = new StreamReader(mem2).ReadToEndAsync().Result, ProcessingTime = sw.Elapsed, ResultCode = context.Response.StatusCode, log_Request = logRequest }; db.log_Response.Add(logResponse); await db.SaveChangesAsync(); } } } 

Response Body可以这种方式记录:

 public class LoggingMiddleware : OwinMiddleware { private static Logger log = LogManager.GetLogger("WebApi"); public LoggingMiddleware(OwinMiddleware next, IAppBuilder app) : base(next) { } public override async Task Invoke(IOwinContext context) { using (var db = new HermesEntities()) { var sw = new Stopwatch(); sw.Start(); var logRequest = new log_Request { Body = new StreamReader(context.Request.Body).ReadToEndAsync().Result, Headers = Json.Encode(context.Request.Headers), IPTo = context.Request.LocalIpAddress, IpFrom = context.Request.RemoteIpAddress, Method = context.Request.Method, Service = "Api", Uri = context.Request.Uri.ToString(), UserName = context.Request.User.Identity.Name }; db.log_Request.Add(logRequest); context.Request.Body.Position = 0; Stream stream = context.Response.Body; MemoryStream responseBuffer = new MemoryStream(); context.Response.Body = responseBuffer; await Next.Invoke(context); responseBuffer.Seek(0, SeekOrigin.Begin); var responseBody = new StreamReader(responseBuffer).ReadToEnd(); //do logging var logResponse = new log_Response { Headers = Json.Encode(context.Response.Headers), Body = responseBody, ProcessingTime = sw.Elapsed, ResultCode = context.Response.StatusCode, log_Request = logRequest }; db.log_Response.Add(logResponse); responseBuffer.Seek(0, SeekOrigin.Begin); await responseBuffer.CopyToAsync(stream); await db.SaveChangesAsync(); } } } 

对于Katana主机,响应主体是默认的只写网络流。 您需要将其替换为MemoryStream ,读取流,记录内容,然后将内存流内容复制回原始网络流。 顺便说一句,如果您的中间件读取请求正文,则下游组件不能,除非请求正文被缓冲。 因此,您可能还需要考虑缓冲请求主体。 如果你想看一些代码, http://lbadri.wordpress.com/2013/08/03/owin-authentication-middleware-for-hawk-in-thinktecture-identitymodel-45/可能是一个起点。 查看HawkAuthenticationHandler类。

我已经通过将请求体写入OWIN环境字典的动作属性解决了这个问题。 之后,日志记录中间件可以通过密钥访问它。

 public class LogResponseBodyInterceptorAttribute : ActionFilterAttribute { public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken) { if (actionExecutedContext?.Response?.Content is ObjectContent) { actionExecutedContext.Request.GetOwinContext().Environment["log-responseBody"] = await actionExecutedContext.Response.Content.ReadAsStringAsync(); } } } 

然后在中间件中:

 public class RequestLoggingMiddleware { ... private void LogResponse(IOwinContext owinContext) { var message = new StringBuilder() .AppendLine($"{owinContext.Response.StatusCode}") .AppendLine(string.Join(Environment.NewLine, owinContext.Response.Headers.Select(x => $"{x.Key}: {string.Join("; ", x.Value)}"))); if (owinContext.Environment.ContainsKey("log-responseBody")) { var responseBody = (string)owinContext.Environment["log-responseBody"]; message.AppendLine() .AppendLine(responseBody); } var logEvent = new LogEventInfo { Level = LogLevel.Trace, Properties = { {"correlationId", owinContext.Environment["correlation-id"]}, {"entryType", "Response"} }, Message = message.ToString() }; _logger.Log(logEvent); } }