【问题标题】:Response body for request/response Logging请求/响应日志的响应正文
【发布时间】:2014-08-30 16:39:10
【问题描述】:

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

这是我设法达到的程度。

我一直在阅读 response.body。说:

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

【问题讨论】:

  • 你搞定了吗?
  • 有点,有一些愚蠢的解决方法,但不是我最初想要的。简而言之 - 没有
  • Thanx - 会调查的
  • @Marty 你确定请求登录也对你有用吗?没有办法 context.Request.Body.Position = 0;将在 context.Request.Body 非搜索流上工作。

标签: c# asp.net-web-api owin


【解决方案1】:

可以通过这种方式记录响应正文:

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 我尝试用内存流替换正文,但随后 api 停止工作。不返回任何结果。任何想法为什么?
    • 确保将内存流中的内容推送回网络流。否则,客户端将不会收到任何响应。在我给出的博文中,查看TeardownCore
    【解决方案3】:

    我通过将请求正文写入 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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多