.Net6 WebApi传入传出参数记录

前言:这个功能主要是用来记录WebApi的所有调用记录,会把所有的传入参数以及得到的结果保存下来,方便问题跟踪(跟前面写的Winform操作日志记录遥相呼应,对系统端到端实现完整记录)。
为了简单易用,这里主要采用中间件的方式来实现。同时考虑了某些情况下并不需要记录,所以加入了忽略某些Action的方法(比如一些需要不间断循环调用的接口),不过我是直接写到中间件里面了。可以考虑其他方式实现高可用性。.
  1. 首先创建一个中间件,并定义以下字段。其中ignoreActions就是不需要记录的一些函数名;_serviceScopeFactory是为了拿到依赖注入的对象实现数据存储的。
    
     
    public class WebApiLog { readonly RequestDelegate _next; readonly IServiceScopeFactory _serviceScopeFactory; readonly List<string> ignoreActions = new List<string>{ "Index1","Default/Index2" }; public WebApiLog(RequestDelegate next, IServiceScopeFactory serviceScopeFactory) { _next = next; _serviceScopeFactory = serviceScopeFactory; }
  1. 传入参数的记录,由于WebApi的传入类型可以是多样性的,如:FromForm、FromBody等,所以对context.Request进行了判断,并采用了不同的数据组合方式
    
     
    public async Task InvokeAsync(HttpContext context) {if (!ignoreActions.Exists(s=>context.Request.Path.ToString().Contains(s))) { //首先记录一些基本的参数,IP,Action,Time等 TApilog Apilog = new TApilog(); Apilog.Ip = Convert.ToString(context.Connection.RemoteIpAddress); Apilog.Action = context.Request.Path; Apilog.Intime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); using var scope = _serviceScopeFactory.CreateScope(); string token = context.Request.Headers["token"]; if (!string.IsNullOrEmpty(token)) { var tokenService = scope.ServiceProvider.GetRequiredService<ITokenService>(); Apilog.Useraccount = tokenService.ParseToken(context)?.UserAccount; } #region 传入参数解析 StringBuilder inarg = new StringBuilder(); if (context.Request.HasFormContentType) { foreach (var item in context.Request.Form) { inarg.AppendLine(item.Key + ":" + item.Value); } } else if (context.Request.Query.Count > 0) { foreach (var item in context.Request.Query) { inarg.AppendLine(item.Key + ":" + item.Value); } } else { context.Request.EnableBuffering(); StreamReader streamReader = new StreamReader(context.Request.Body); inarg.AppendLine(await streamReader.ReadToEndAsync()); context.Request.Body.Seek(0, SeekOrigin.Begin); } Apilog.Input = inarg.ToString(); #endregion
  1. 传出参数的记录
    
     
    #region 传出参数解析 var originalBodyStream = context.Response.Body; using (var responseBody = new MemoryStream()) { context.Response.Body = responseBody; await _next(context); Apilog.Output = await GetResponse(context.Response); await responseBody.CopyToAsync(originalBodyStream); } #endregion Apilog.Outtime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); var _tApilogServices = scope.ServiceProvider.GetRequiredService<ITApilogServices>(); try {await _tApilogServices.InsertAsync(Apilog); } catch { } } else { await _next(context); }}public async Task<string> GetResponse(HttpResponse response) { response.Body.Seek(0, SeekOrigin.Begin); var text = await new StreamReader(response.Body).ReadToEndAsync(); response.Body.Seek(0, SeekOrigin.Begin); return text; }
  1. 最后在Program文件中使用这个中间件
    
     
    //日志记录app.UseMiddleware<WebApiLog>();
  1. 结束。最后补充下,因为这里是记录到数据库的,所以字段长度在设计的时候要足够,同时因为这个表查询频率不高,可以不建任何索引(这个表空间的增长速度会非常快,所以个人认为没必要增加开销)