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

2023-11-22 06:48

本文主要是介绍.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"];//记得添加UAParservar 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

这篇关于.Net5 框架搭建(四):基于ActionFilter记录操作日志的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/408282

相关文章

Spring Retry 实现乐观锁重试实践记录

《SpringRetry实现乐观锁重试实践记录》本文介绍了在秒杀商品SKU表中使用乐观锁和MybatisPlus配置乐观锁的方法,并分析了测试环境和生产环境的隔离级别对乐观锁的影响,通过简单验证,... 目录一、场景分析 二、简单验证 2.1、可重复读 2.2、读已提交 三、最佳实践 3.1、配置重试模板

在 Spring Boot 中使用异步线程时的 HttpServletRequest 复用问题记录

《在SpringBoot中使用异步线程时的HttpServletRequest复用问题记录》文章讨论了在SpringBoot中使用异步线程时,由于HttpServletRequest复用导致... 目录一、问题描述:异步线程操作导致请求复用时 Cookie 解析失败1. 场景背景2. 问题根源二、问题详细分

SpringBoot项目注入 traceId 追踪整个请求的日志链路(过程详解)

《SpringBoot项目注入traceId追踪整个请求的日志链路(过程详解)》本文介绍了如何在单体SpringBoot项目中通过手动实现过滤器或拦截器来注入traceId,以追踪整个请求的日志链... SpringBoot项目注入 traceId 来追踪整个请求的日志链路,有了 traceId, 我们在排

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型的操作流程

《0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeekR1模型的操作流程》DeepSeekR1模型凭借其强大的自然语言处理能力,在未来具有广阔的应用前景,有望在多个领域发... 目录0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型,3步搞定一个应

关于Spring @Bean 相同加载顺序不同结果不同的问题记录

《关于Spring@Bean相同加载顺序不同结果不同的问题记录》本文主要探讨了在Spring5.1.3.RELEASE版本下,当有两个全注解类定义相同类型的Bean时,由于加载顺序不同,最终生成的... 目录问题说明测试输出1测试输出2@Bean注解的BeanDefiChina编程nition加入时机总结问题说明

Spring Boot整合log4j2日志配置的详细教程

《SpringBoot整合log4j2日志配置的详细教程》:本文主要介绍SpringBoot项目中整合Log4j2日志框架的步骤和配置,包括常用日志框架的比较、配置参数介绍、Log4j2配置详解... 目录前言一、常用日志框架二、配置参数介绍1. 日志级别2. 输出形式3. 日志格式3.1 PatternL

轻松上手MYSQL之JSON函数实现高效数据查询与操作

《轻松上手MYSQL之JSON函数实现高效数据查询与操作》:本文主要介绍轻松上手MYSQL之JSON函数实现高效数据查询与操作的相关资料,MySQL提供了多个JSON函数,用于处理和查询JSON数... 目录一、jsON_EXTRACT 提取指定数据二、JSON_UNQUOTE 取消双引号三、JSON_KE

修改若依框架Token的过期时间问题

《修改若依框架Token的过期时间问题》本文介绍了如何修改若依框架中Token的过期时间,通过修改`application.yml`文件中的配置来实现,默认单位为分钟,希望此经验对大家有所帮助,也欢迎... 目录修改若依框架Token的过期时间修改Token的过期时间关闭Token的过期时js间总结修改若依