.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,結束!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM