zoukankan      html  css  js  c++  java
  • .NET CORE之API日志收集

    我们在构建WEBAPI项目时,通常需要构建一个全局的记录API 请求和返回 的功能,在WEBAPI框架下 我们通过自定义一个DelegateHandler来实现这个功能,

    在.NET CORE框架下已经不存在DelegateHandler管道了,我们需要通过Middleware管道来实现。具体实现如下:

    定义LoggingMiddleware

        public class GlobalApiLoggingMiddleware : IMiddleware
        {
            private readonly ILogger _logger;
    
            public GlobalApiLoggingMiddleware(ILoggerFactory loggerFactory)
            {
                _logger = loggerFactory.CreateLogger("ApiLog");
            }
            public async Task InvokeAsync(HttpContext context, RequestDelegate next)
            {
            //在这里我们来拦截请求,收集日志
     await next.Invoke(context);
    }
    }

    HttpContext的定义

    可以看到里面的Request和Response对象 分别时 HttpRequest 和 HttpResponse,不再像在webapi框架下直接通过HttpRequestMessage、HttpResponseMessage来获取请求报文和返回报文。

    这里需要花费一些技巧。

    获取请求报文,

                //reuqest支持buff,否则body只能读取一次
                context.Request.EnableBuffering();
                //这里不要释放stream,否则后续读取request.body会报错
                var reader = new StreamReader(context.Request.Body, Encoding.UTF8);
                var requestStr = await reader.ReadToEndAsync();
                //var requestStr = reader.ReadToEnd(); 升级.net core 3.1后 会报 Synchronous operations are disallowed. 错误

    首先类似于webapi框架下获取请求报文一样,需要先设置request buffer,这样request报文可以读取多次

    其次获取报文的方式 是通过 stream获取,这里stream不要释放 不要释放 不要释放。重要的事情说三次。

    获取返回报文 更加复杂一点

               Stream originalBody = context.Response.Body;
    
                try
                {
                    using (var memStream = new MemoryStream())
                    {
                        context.Response.Body = memStream;
                        await next.Invoke(context);
    
                        var request = context.Request;
                        var log = new ApiLogEntity()
                        {
                            Appkey = request.GetAppkey(),
                            ClientIp = request.GetClientRealIp(),
                            HttpMethod = request.Method,
                            Request = requestStr,
                            RequestId = request.GetRequestId(),
                            RequestUrl = request.Path.Value,
                            QueryString = request.QueryString.Value,
                            ServerIp = request.Host.Value,
                            StatusCode = context.Response.StatusCode
                        };
    
                        memStream.Position = 0;
                        log.Response = await new StreamReader(memStream).ReadToEndAsync();
    
                        memStream.Position = 0;
                        await memStream.CopyToAsync(originalBody);
    
                        _logger.LogInformation(JsonConvert.SerializeObject(log));
                    }
                }
                finally
                {
                    //重新给response.body赋值,用于返回
                    context.Response.Body = originalBody;
                }

    这里HttpResponse的body是不允许读取的!!所以这里的策略是 先给body赋值一个新的stream,

    执行完action得到返回值后,可以读取我们自己定义的stream拿到返回报文

    最后把返回值stream copy给原来的body对象,并重新赋给context.Response.Body,这里客户端可以正确返回了。

    OK,结束!

  • 相关阅读:
    poj1019
    poj1017
    .net面试题及答案二
    .net面试题集锦一
    .net面试题目三
    ADO.NET中的五个主要对象
    ASP.NET页面生命周期描述(转)
    学习网址不断更新。。。
    Html5新标签解释及用法
    HTML5 Shiv – 让该死的IE系列支持HTML5吧
  • 原文地址:https://www.cnblogs.com/gt1987/p/10981343.html
Copyright © 2011-2022 走看看