隐藏

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

发布:2022/4/3 0:34:31作者:管理员 来源:本站 浏览次数:1515

以前 .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 ();

       }


复制代码