巧用ActionFilterAttribute实现API日志的记录

本文介绍了如何在ASP.NET Core中通过创建一个自定义的Filter,名为`LogAttribute`,来记录API的输入输出信息及执行耗时。在`OnActionExecuting`方法中捕获请求体和参数,在`OnActionExecuted`方法中记录响应结果和执行时间,并利用NLogger进行日志输出。这种方式有助于后期问题排查和性能分析。
摘要由CSDN通过智能技术生成

背景

上回提到开发web api的时候,一般是需要记录api的输入输出信息,方便后续排查问题;使用的是委托的形式进行记录日志。

使用Func<T, TResult> 委托实现API日志的记录

这次我们使用另外一种方式,Filter来记录输入输出日志。

实现方式

1、首先在进入action的时候,定义OnActionExecuting。

    public override void OnActionExecuting(ActionExecutingContext context)
        {
            base.OnActionExecuting(context);


            // 后续添加了获取请求的请求体,如果在实际项目中不需要删除即可
            long contentLen = context.HttpContext.Request.ContentLength == null ? 0 : context.HttpContext.Request.ContentLength.Value;
            if (contentLen > 0)
            {
                // 读取请求体中所有内容
                System.IO.Stream stream = context.HttpContext.Request.Body;
                if (context.HttpContext.Request.Method == "POST")
                {
                    stream.Position = 0;
                }
                byte[] buffer = new byte[contentLen];
                stream.Read(buffer, 0, buffer.Length);
                // 转化为字符串
                RequestBody = System.Text.Encoding.UTF8.GetString(buffer);
            }


            ActionArguments = Newtonsoft.Json.JsonConvert.SerializeObject(context.ActionArguments);


            Stopwatch = new Stopwatch();
            Stopwatch.Start();
        }

2、定义Stopwatch ,计算方法的耗时。

  private string ActionArguments { get; set; }


        /// <summary>
        /// 请求体中的所有值
        /// </summary>
        private string RequestBody { get; set; }


        private Stopwatch Stopwatch { get; set; }

3、结束的时候,把信息打印出来OnActionExecuted。

  public override void OnActionExecuted(ActionExecutedContext context)
        {
            base.OnActionExecuted(context);
            Stopwatch.Stop();


            string url = context.HttpContext.Request.Host + context.HttpContext.Request.Path + context.HttpContext.Request.QueryString;
            string method = context.HttpContext.Request.Method;
            string controller = context.Controller.ToString();
            string action = context.ActionDescriptor.DisplayName;
            string token = "";
            if (context.HttpContext.Request != null && context.HttpContext.Request.Headers != null && context.HttpContext.Request.Headers["Authorization"].Count > 0)
            {
                token = context.HttpContext.Request.Headers["Authorization"];
            }
            string qs = ActionArguments;
            dynamic result = context?.Result?.GetType()?.Name == "EmptyResult" ? new { Value = "无返回结果" } : context?.Result as dynamic;


            string res = "在返回结果前发生了异常";
            try
            {
                if (result != null)
                {
                    res = Newtonsoft.Json.JsonConvert.SerializeObject(result.Value);
                }
            }
            catch (System.Exception)
            {
                res = "日志未获取到结果,返回的数据无法序列化";
            }


            NLogger.Info(
                $"地址:{url} \n " +
                  $"controller:{controller} \n " +
                    $"action:{action} \n " +
                      $"token:{token} \n " +
                $"方式:{method} \n " +
                $"请求体:{RequestBody} \n " +
                $"参数:{qs}\n " +
                $"结果:{res}\n " +
                $"耗时:{Stopwatch.Elapsed.TotalMilliseconds} 毫秒(指控制器内对应方法执行完毕的时间)");
        }

4、控制器调用LogAttribute。

/// <summary>
    ///
    /// </summary>
    [Produces("application/json")]
    [LogAttribute]
    [CustomExceptionFilterAttribute]
    public class DefaultController : Controller
    {
    }

完整代码

using CompanyName.ProjectName.Core;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Diagnostics;


namespace CompanyName.ProjectName.HttpApi.Host.Code
{
    /// <summary>
    /// 拦截器
    /// </summary>
    public class LogAttribute : ActionFilterAttribute
    {
        private string ActionArguments { get; set; }


        /// <summary>
        /// 请求体中的所有值
        /// </summary>
        private string RequestBody { get; set; }


        private Stopwatch Stopwatch { get; set; }


        /// <summary>
        ///
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            base.OnActionExecuting(context);


            // 后续添加了获取请求的请求体,如果在实际项目中不需要删除即可
            long contentLen = context.HttpContext.Request.ContentLength == null ? 0 : context.HttpContext.Request.ContentLength.Value;
            if (contentLen > 0)
            {
                // 读取请求体中所有内容
                System.IO.Stream stream = context.HttpContext.Request.Body;
                if (context.HttpContext.Request.Method == "POST")
                {
                    stream.Position = 0;
                }
                byte[] buffer = new byte[contentLen];
                stream.Read(buffer, 0, buffer.Length);
                // 转化为字符串
                RequestBody = System.Text.Encoding.UTF8.GetString(buffer);
            }


            ActionArguments = Newtonsoft.Json.JsonConvert.SerializeObject(context.ActionArguments);


            Stopwatch = new Stopwatch();
            Stopwatch.Start();
        }


        /// <summary>
        ///
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            base.OnActionExecuted(context);
            Stopwatch.Stop();


            string url = context.HttpContext.Request.Host + context.HttpContext.Request.Path + context.HttpContext.Request.QueryString;
            string method = context.HttpContext.Request.Method;
            string controller = context.Controller.ToString();
            string action = context.ActionDescriptor.DisplayName;
            string token = "";
            if (context.HttpContext.Request != null && context.HttpContext.Request.Headers != null && context.HttpContext.Request.Headers["Authorization"].Count > 0)
            {
                token = context.HttpContext.Request.Headers["Authorization"];
            }
            string qs = ActionArguments;
            dynamic result = context?.Result?.GetType()?.Name == "EmptyResult" ? new { Value = "无返回结果" } : context?.Result as dynamic;


            string res = "在返回结果前发生了异常";
            try
            {
                if (result != null)
                {
                    res = Newtonsoft.Json.JsonConvert.SerializeObject(result.Value);
                }
            }
            catch (System.Exception)
            {
                res = "日志未获取到结果,返回的数据无法序列化";
            }


            NLogger.Info(
                $"地址:{url} \n " +
                  $"controller:{controller} \n " +
                    $"action:{action} \n " +
                      $"token:{token} \n " +
                $"方式:{method} \n " +
                $"请求体:{RequestBody} \n " +
                $"参数:{qs}\n " +
                $"结果:{res}\n " +
                $"耗时:{Stopwatch.Elapsed.TotalMilliseconds} 毫秒(指控制器内对应方法执行完毕的时间)");
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值