2014-08-30 8 views
5

Ich versuche eine OWIN Middleware-Komponente zu schreiben, die jede eingehende Anfrage und jede Antwort auf die Datenbank protokolliert.Response Body für Anfrage/Antwort Logging

Hier ist, wie weit ich es geschafft habe zu bekommen.

Ich blieb beim Lesen des Response.body stecken. Sagt:

Stream unterstützt nicht lesen.

Wie kann ich den Response.Body lesen?

+0

Hast du diese Arbeit? –

+0

Art von, mit einigen dummen Arbeiten um, aber nicht so, wie ich ursprünglich wollte. Kurz gesagt - NO – Marty

+2

Dies löste es für mich: http://stackoverflow.com/questions/26214113/how-can-i-safely-intercept-the-response-stream-in-a-custom-owin-middleware –

Antwort

7

Antworttext ist standardmäßig ein schreibgeschützter Netzwerkstream für Katana-Hosts. Sie müssen es durch eine MemoryStream ersetzen, den Stream lesen, den Inhalt protokollieren und dann den Inhalt des Speicher-Streams wieder in den ursprünglichen Netzwerk-Stream kopieren. Wenn Ihre Middleware den Anfragetext liest, können Downstream-Komponenten nicht, sofern der Anfragetext nicht gepuffert ist. Daher müssen Sie möglicherweise auch den Anfragetext puffern. Wenn Sie sich etwas Code ansehen möchten, könnte http://lbadri.wordpress.com/2013/08/03/owin-authentication-middleware-for-hawk-in-thinktecture-identitymodel-45/ ein Ausgangspunkt sein. Schauen Sie sich die Klasse HawkAuthenticationHandler an.

+0

Ich habe versucht, den Körper mit einem Speicher-Stream zu ersetzen, aber dann funktioniert die API nicht mehr. Keine Ergebnisse werden zurückgegeben. Irgendwelche Ideen warum? – Marty

+2

Stellen Sie sicher, dass Sie den Inhalt aus dem Speicherstream zurück in den Netzwerkstream übertragen. Andernfalls erhält der Client keine Antwort. In dem Blogbeitrag, den ich gegeben habe, schau dir 'TeardownCore' an. – Badri

7

Antwortkörper kann auf diese Weise protokolliert werden:

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

ich gelöst habe das Problem durch eine Aktion Anwendung Attribut die Anfrage Körper OWIN Umgebung Wörterbuch zu schreiben. Danach kann die Protokollierungs-Middleware über einen Schlüssel darauf zugreifen.

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

Und dann in der 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); 
    } 
} 
Verwandte Themen