.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

相关文章

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

Spring Boot集成/输出/日志级别控制/持久化开发实践

《SpringBoot集成/输出/日志级别控制/持久化开发实践》SpringBoot默认集成Logback,支持灵活日志级别配置(INFO/DEBUG等),输出包含时间戳、级别、类名等信息,并可通过... 目录一、日志概述1.1、Spring Boot日志简介1.2、日志框架与默认配置1.3、日志的核心作用

java中pdf模版填充表单踩坑实战记录(itextPdf、openPdf、pdfbox)

《java中pdf模版填充表单踩坑实战记录(itextPdf、openPdf、pdfbox)》:本文主要介绍java中pdf模版填充表单踩坑的相关资料,OpenPDF、iText、PDFBox是三... 目录准备Pdf模版方法1:itextpdf7填充表单(1)加入依赖(2)代码(3)遇到的问题方法2:pd

Python操作PDF文档的主流库使用指南

《Python操作PDF文档的主流库使用指南》PDF因其跨平台、格式固定的特性成为文档交换的标准,然而,由于其复杂的内部结构,程序化操作PDF一直是个挑战,本文主要为大家整理了Python操作PD... 目录一、 基础操作1.PyPDF2 (及其继任者 pypdf)2.PyMuPDF / fitz3.Fre

Python极速搭建局域网文件共享服务器完整指南

《Python极速搭建局域网文件共享服务器完整指南》在办公室或家庭局域网中快速共享文件时,许多人会选择第三方工具或云存储服务,但这些方案往往存在隐私泄露风险或需要复杂配置,下面我们就来看看如何使用Py... 目录一、android基础版:HTTP文件共享的魔法命令1. 一行代码启动HTTP服务器2. 关键参

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

MySQL 强制使用特定索引的操作

《MySQL强制使用特定索引的操作》MySQL可通过FORCEINDEX、USEINDEX等语法强制查询使用特定索引,但优化器可能不采纳,需结合EXPLAIN分析执行计划,避免性能下降,注意版本差异... 目录1. 使用FORCE INDEX语法2. 使用USE INDEX语法3. 使用IGNORE IND

Python Web框架Flask、Streamlit、FastAPI示例详解

《PythonWeb框架Flask、Streamlit、FastAPI示例详解》本文对比分析了Flask、Streamlit和FastAPI三大PythonWeb框架:Flask轻量灵活适合传统应用... 目录概述Flask详解Flask简介安装和基础配置核心概念路由和视图模板系统数据库集成实际示例Stre

Olingo分析和实践之OData框架核心组件初始化(关键步骤)

《Olingo分析和实践之OData框架核心组件初始化(关键步骤)》ODataSpringBootService通过初始化OData实例和服务元数据,构建框架核心能力与数据模型结构,实现序列化、URI... 目录概述第一步:OData实例创建1.1 OData.newInstance() 详细分析1.1.1