ASP.NET Core 入門(2)(WebApi接口請求日志 Request和Response)


以前 .NET Framework WebApi 記錄接口訪問日志,一般是通過Filter的方式進行攔截,通過重寫ActionFilterAttribute的OnActionExecuting實現攔截記錄Request內容,通過重寫OnActionExecuted實現攔截記錄Response內容,具體實現代碼就不貼了。這篇簡單介紹.Net Core WebApi 下通過中間件的攔截方式記錄接口訪問日志,關鍵部分是通過讀取獲取 Request.Body 時需要開啟 Request.EnableRewind () 啟用倒帶功能;讀取 Response.Body 時需要用到的技巧,詳細看代碼。該例子中我使用的日志組件是Log4Net,獲取到的信息通過Log4Net保存到本地文件。

 

創建日志類

using System;
using System.Collections.Generic;
using System.Linq;

namespace DYDGame.Web.Host
{
    public class RequestResponseLog
    {
        public string Url {get;set;}
        public IDictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
        public string Method { get; set; }
        public string RequestBody { get; set; }
        public string ResponseBody  { get; set; }
        public DateTime ExcuteStartTime { get; set; }
        public DateTime ExcuteEndTime { get; set; }
        public override string ToString()
        {
            string headers = "[" + string.Join(",", this.Headers.Select(i => "{" + $"\"{i.Key}\":\"{i.Value}\"" + "}")) + "]";
            return $"Url: {this.Url},\r\nHeaders: {headers},\r\nMethod: {this.Method},\r\nRequestBody: {this.RequestBody},\r\nResponseBody: {this.ResponseBody},\r\nExcuteStartTime: {this.ExcuteStartTime.ToString("yyyy-MM-dd HH:mm:ss.fff")},\r\nExcuteStartTime: {this.ExcuteEndTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}";
        }
    }
}

 

創建記錄接口日志中間件 Middleware

using System;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Text;
using System.Threading;
using DYDGame.Utility;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;

namespace DYDGame.Web.Host {
    public class RequestResponseLoggingMiddleware {
        private readonly RequestDelegate _next;
        private RequestResponseLog _logInfo;

        public RequestResponseLoggingMiddleware (RequestDelegate next) {
            _next = next;
        }

        public async Task Invoke (HttpContext context) {
            _logInfo = new RequestResponseLog ();

            HttpRequest request = context.Request;
            _logInfo.Url = request.Path.ToString ();
            _logInfo.Headers = request.Headers.ToDictionary (k => k.Key, v => string.Join (";", v.Value.ToList ()));
            _logInfo.Method = request.Method;
            _logInfo.ExcuteStartTime = DateTime.Now;

            //獲取request.Body內容
            if (request.Method.ToLower ().Equals ("post")) {

                request.EnableRewind (); //啟用倒帶功能,就可以讓 Request.Body 可以再次讀取

                Stream stream = request.Body;
                byte[] buffer = new byte[request.ContentLength.Value];
                stream.Read (buffer, 0, buffer.Length);
                _logInfo.RequestBody = Encoding.UTF8.GetString (buffer);

                request.Body.Position = 0;
                
            } else if (request.Method.ToLower ().Equals ("get")) {
                _logInfo.RequestBody = request.QueryString.Value;
            }

            //獲取Response.Body內容
            var originalBodyStream = context.Response.Body;

            using (var responseBody = new MemoryStream ()) {
                context.Response.Body = responseBody;

                await _next (context);

                _logInfo.ResponseBody = await FormatResponse (context.Response);
                _logInfo.ExcuteEndTime = DateTime.Now;
                Log4Net.LogInfo ($"VisitLog: {_logInfo.ToString()}");

                await responseBody.CopyToAsync (originalBodyStream);
            }
        }

        private async Task<string> FormatResponse (HttpResponse response) {
            response.Body.Seek (0, SeekOrigin.Begin);
            var text = await new StreamReader (response.Body).ReadToEndAsync ();
            response.Body.Seek (0, SeekOrigin.Begin);

            return text;
        }
    }

    public static class RequestResponseLoggingMiddlewareExtensions {
        public static IApplicationBuilder UseRequestResponseLogging (this IApplicationBuilder builder) {
            return builder.UseMiddleware<RequestResponseLoggingMiddleware> ();
        }
    }
}

 

把中間件添加到管道中 Pipeline

在 Startup.cs 添加
        public void Configure (IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {
            if (env.IsDevelopment ()) {
                app.UseDeveloperExceptionPage ();
            } else {
                app.UseHsts ();
            }

            loggerFactory.AddLog4Net ();
            app.UseRequestResponseLogging();
            
            // app.UseHttpsRedirection();
            app.UseMvc ();
        }

 

 


免責聲明!

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



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