Response body for request / response Logging

I am trying to write an Owin mid-tier component that will record every incoming request and response to the database.

This is how far I managed to get.

I am stuck in reading the answer. Is talking:

The stream does not support reading.

How can I read 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(); } } } 
+5
source share
3 answers

The response body is the default write-only network stream for Katana hosts. You will need to replace it with a MemoryStream , read the stream, register the contents and then copy the contents of the memory stream back to the original network stream. BTW, if your middleware reads the request body, the downstream components cannot, unless the request body is buffered. Thus, you may also need to buffer the request body. If you want to see some kind of code, http://lbadri.wordpress.com/2013/08/03/owin-authentication-middleware-for-hawk-in-thinktecture-identitymodel-45/ can be a starting point. Take a look at the HawkAuthenticationHandler class.

+7
source

The response body can be logged as follows:

 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(); } } } 
+7
source

I solved the problem by applying the action attribute, which writes the request body to the OWIN environment dictionary. After that, the logging middleware can access it using a key.

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

And then in the middleware:

 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); } } 
+1
source

Source: https://habr.com/ru/post/1201478/


All Articles