2014-08-30 15 views
5

Я пытаюсь написать компонент средней нагрузки Owin, который будет записывать каждый входящий запрос и ответ на базу данных.Тело ответа для запроса/ответа Ведение журнала

Вот как далеко я успел добраться.

Я застрял на чтении ответа. Says:

Поток не поддерживает чтение.

Как я могу прочитать 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(); 
     } 
    } 
} 
+0

ли вы получить эту работу? –

+0

вид, с некоторыми глупыми работами вокруг, но не так, как я изначально хотел. Короче - NO – Marty

+2

Это разрешило это для меня: http://stackoverflow.com/questions/26214113/how-can-i-safely-intercept-the-response-stream-in-a-custom-owin-middleware –

ответ

7

Тело ответа является сетевым потоком только для записи по умолчанию для хостов Katana. Вам нужно будет заменить его MemoryStream, прочитать поток, зарегистрировать содержимое и затем скопировать содержимое потока памяти обратно в исходный сетевой поток. BTW, если ваше промежуточное программное обеспечение считывает тело запроса, нисходящие компоненты не могут, если тело запроса не буферизовано. Таким образом, вам может потребоваться также буферизация тела запроса. Если вы хотите посмотреть какой-то код, http://lbadri.wordpress.com/2013/08/03/owin-authentication-middleware-for-hawk-in-thinktecture-identitymodel-45/ может быть отправной точкой. Посмотрите на класс HawkAuthenticationHandler.

+0

Я попытался заменить тело потоком памяти, но тогда api перестанет работать. Результаты не возвращаются. Любые идеи почему? – Marty

+2

Убедитесь, что вы удаляете содержимое из потока памяти обратно в сетевой поток. В противном случае клиент не получит ответа. В сообщении в блоге, которое я дал, посмотрите на «TeardownCore». – Badri

7

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

Я решил эту проблему путем применения действий атрибута записи тела запроса 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); 
    } 
} 
Смежные вопросы