.Net5 框架搭建(四):基于ActionFilter记录操作日志

前言

在上篇文章《.Net5 框架搭建(三):基于ExceptionFilter+NLog封装异常日志收集》中我们提到了过滤器,也对异常信息做了日志记录,本文接着对五大过滤器中的操作过滤器Action Filter进一步实战功能的延续。
问:那么什么业务场景适合用到操作过滤器呢?
答:日志统计、权限过滤

ActionFilter/操作过滤器

官网截图
官网
大致意思,提供两种接口IActionFilter 或 IAsyncActionFilter 接口。

1、IActionFilter
这个接口提供两个方法
OnActionExecuted(ActionExecutedContext) 在操作执行之后、操作结果之前调用。

OnActionExecuting(ActionExecutingContext) 在模型绑定完成后,在执行操作之前调用。

2、IAsyncActionFilter
只提供一种方法
OnActionExecutionAsync(ActionExecutingContext, ActionExecutionDelegate)
模型绑定完成后,在操作之前以异步方式调用。

创建一个自定义操作过滤器

这里我是继承了IAsyncActionFilter,就是为了省麻烦
LogActionFilter.cs

    /// <summary>
    /// 操作日志过滤器
    /// </summary>
    public class LogActionFilter : IAsyncActionFilter
    {
        private readonly ILogHandler _logHandler;

        public LogActionFilter(ILogHandler logHandler)
        {
            _logHandler = logHandler;
        }

        public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            if (context.ActionDescriptor.EndpointMetadata.Any(m => m.GetType() == typeof(NoLogAttribute)))
            {
                return next();
            }

            return _logHandler.LogAsync(context, next);
        }
    }

新增一个自定义属性类,用于区别一些不想做操作日志记录的方法
NoLogAttribute.cs

    /// <summary>
    /// 不记录操作日志的属性
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
    public class NoLogAttribute : Attribute
    {
    }

LogHandler.cs

    /// <summary>
    /// 操作日志处理
    /// </summary>
    public class LogHandler : ILogHandler
    {
        private readonly ILogger _logger;
        private readonly ISystemOperateLogBLL _systemOperateLogBLL;

        public LogHandler(ILogger<LogHandler> logger, ISystemOperateLogBLL systemOperateLogBLL)
        {
            _logger = logger;
            _systemOperateLogBLL = systemOperateLogBLL;
        }

        public async Task LogAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            var sw = new Stopwatch();
            sw.Start();
            var actionExecutedContext = await next();
            sw.Stop();

            //操作参数
            var args = JsonConvert.SerializeObject(context.ActionArguments);
            //操作结果
            //var result1 = JsonConvert.SerializeObject(actionResult?.Value);

            try
            {
                var model = new SystemOperateLog
                {
                    Params = args,
                    ApiMethod = context.HttpContext.Request.Method.ToLower(),
                    ApiPath = context.ActionDescriptor.AttributeRouteInfo.Template.ToLower(),
                    ElapsedMilliseconds = sw.ElapsedMilliseconds.ObjToInt()
                };
                ObjectResult result = actionExecutedContext.Result as ObjectResult;
                if (result != null)
                {
                    model.Result = JsonConvert.SerializeObject(result.Value);
                    model.LogStatus = 1;
                }
                string ua = context.HttpContext.Request.Headers["User-Agent"];
                //记得添加UAParser
                var client = UAParser.Parser.GetDefault().Parse(ua);
                var device = client.Device.Family;
                device = device.ToLower() == "other" ? "" : device;
                model.Browser = client.UA.Family;
                model.Os = client.OS.Family;
                model.Device = device;
                model.BrowserInfo = ua;
                model.IP = IPHelper.GetIP(context?.HttpContext?.Request);
                await _systemOperateLogBLL.AddLog(model);
            }
            catch (Exception ex)
            {
                _logger.LogError("操作日志插入异常:{@ex}", ex);
            }
        }
    }

ILogHandler.cs

    /// <summary>
    /// 操作日志处理接口
    /// </summary>
    public interface ILogHandler
    {
        /// <summary>
        /// 写操作日志
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        Task LogAsync(ActionExecutingContext context, ActionExecutionDelegate next);
    }

IPHelper.cs

    public class IPHelper
    {
        /// <summary>
        /// 是否为ip
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        public static bool IsIP(string ip)
        {
            return Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");
        }

        /// <summary>
        /// 获得IP地址
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public static string GetIP(HttpRequest request)
        {
            if (request == null)
            {
                return "";
            }
            
            string ip = request.Headers["X-Real-IP"].FirstOrDefault();
            if (!ip.IsNotEmptyOrNull())
            {
                ip = request.Headers["X-Forwarded-For"].FirstOrDefault();
            }
            if (!ip.IsNotEmptyOrNull())
            {
                ip = request.HttpContext?.Connection?.RemoteIpAddress?.ToString();
            }
            if (!ip.IsNotEmptyOrNull() || !IsIP(ip.Split(":")[0]))
            {
                ip = "127.0.0.1";
            }

            return ip;
        }

        /// <summary>
        /// 获得MAC地址
        /// </summary>
        /// <returns></returns>
        public static string GetMACIp()
        {
            //本地计算机网络连接信息
            //IPGlobalProperties computerProperties = IPGlobalProperties.GetIPGlobalProperties();
            //获取本机电脑名
            //var HostName = computerProperties.HostName;
            //获取域名
            //var DomainName = computerProperties.DomainName;

            //获取本机所有网络连接
            NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();

            if (nics == null || nics.Length < 1)
            {
                return "";
            }

            var MACIp = "";
            foreach (NetworkInterface adapter in nics)
            {
                var adapterName = adapter.Name;

                var adapterDescription = adapter.Description;
                var NetworkInterfaceType = adapter.NetworkInterfaceType;
                if (adapterName == "本地连接" || adapterName == "WLAN")
                {
                    PhysicalAddress address = adapter.GetPhysicalAddress();
                    byte[] bytes = address.GetAddressBytes();

                    for (int i = 0; i < bytes.Length; i++)
                    {
                        MACIp += bytes[i].ToString("X2");

                        if (i != bytes.Length - 1)
                        {
                            MACIp += "-";
                        }
                    }
                }
            }

            return MACIp;
        }
    }

全局注册

            services.AddControllers(options =>
            {
                //添加全局异常过滤器
                options.Filters.Add<GlobalExceptionsFilter>();
                //日志过滤器
                options.Filters.Add<LogActionFilter>();
            });

测试

        [HttpGet("getUser")]
        public async Task<dynamic> Get(long id)
        {
            //_logger.LogError("LogError3333");
            var obj = await _systemUserBLL.GetUser(id);
            return obj;
        }
        [NoLog]
        [HttpPost("updateUser")]
        public dynamic UpdateUser(SystemUser user)
        {
            var obj = _systemUserBLL.Update(user);
            return obj;
        }

期望效果:记录getUser、不记录updateUser

运行截图

在这里插入图片描述
在这里插入图片描述

完整代码已上传码云:https://gitee.com/shao-jiayong/cuo-ding

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hello,Mr.S

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值