2014-08-30 21 views
5

Tôi đang cố gắng viết một thành phần phần mềm midleware của Owin sẽ LOG mỗi yêu cầu gửi đến và phản hồi lại cơ sở dữ liệu.Nội dung phản hồi cho yêu cầu/phản hồi Ghi nhật ký

Đây là cách tôi quản lý được.

Tôi gặp khó khăn khi đọc phản hồi.body. Nói:

Luồng không hỗ trợ đọc.

Làm cách nào để đọc phản hồi.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(); 
     } 
    } 
} 
+0

Cậu làm việc này? –

+0

loại, với một số công việc ngu ngốc xung quanh, nhưng không phải như tôi ban đầu muốn. Trong ngắn hạn - NO – Marty

+2

Điều này giải quyết nó cho tôi: http://stackoverflow.com/questions/26214113/how-can-i-safely-intercept-the-response-stream-in-a-custom-owin-middleware –

Trả lời

7

Nội dung phản hồi là luồng mạng chỉ ghi mặc định cho máy chủ Katana. Bạn sẽ cần phải thay thế nó bằng một MemoryStream, đọc luồng, đăng nhập nội dung và sau đó sao chép nội dung luồng bộ nhớ trở lại luồng mạng ban đầu. BTW, nếu phần mềm trung gian của bạn đọc phần thân yêu cầu, thì các thành phần hạ lưu không thể, trừ khi phần thân yêu cầu được đệm. Vì vậy, bạn có thể cần phải xem xét việc đệm cơ thể yêu cầu là tốt. Nếu bạn muốn xem một số mã, http://lbadri.wordpress.com/2013/08/03/owin-authentication-middleware-for-hawk-in-thinktecture-identitymodel-45/ có thể là điểm bắt đầu. Nhìn vào lớp HawkAuthenticationHandler.

+0

Tôi đã thử thay thế cơ thể bằng luồng bộ nhớ, nhưng sau đó api ngừng hoạt động. Không có kết quả nào được trả về. Bất kỳ ý tưởng tại sao? – Marty

+2

Đảm bảo bạn đẩy nội dung từ luồng bộ nhớ trở lại luồng mạng. Nếu không, khách hàng sẽ không nhận được phản hồi. Trong bài đăng trên blog tôi đã đưa ra, hãy xem 'TeardownCore'. – Badri

7

đáp ứng cơ thể có thể đăng nhập theo cách này:

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

Tôi đã giải quyết vấn đề bằng cách áp dụng một hành động thuộc tính văn bản cho cơ yêu cầu vào từ điển môi trường OWIN. Sau đó, phần mềm trung gian ghi nhật ký có thể truy cập nó bằng một khóa.

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

Và sau đó trong 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); 
    } 
} 
Các vấn đề liên quan