#region copyright //------------------------------------------------------------------------------ // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 // 此代码版权(除特别声明外的代码)归作者本人Diego所有 // 源代码使用协议遵循本仓库的开源协议及附加协议 // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/ // QQ群:605534569 //------------------------------------------------------------------------------ #endregion using Furion; using Furion.Reflection; using Furion.Reflection.Extensions; using System.Reflection; using System.Text; using ThingsGateway.Admin.Core; using UAParser; namespace ThingsGateway.Admin.Application; /// /// AOP处理操作日志 /// public class OperDispatchProxy : AspectDispatchProxy, IDispatchProxy { /// /// 服务提供器,可以用来解析服务,如:Services.GetService() /// public IServiceProvider Services { get; set; } /// /// 当前服务实例 /// public object Target { get; set; } /// /// 方法 /// /// /// /// /// public override object Invoke(MethodInfo method, object[] args) { var desc = Target.GetCustomAttribute(method.ToString(), true); if (desc == null) { return Invoke(method, args); } else { Exception exception = default; object result = default; try { result = Invoke(method, args); } catch (Exception ex) { exception = ex; } WriteOperLog(method, args, desc, result, exception); if (exception != null) { throw exception; } return result;//返回结果 } object Invoke(MethodInfo method, object[] args) { //如果不带返回值 if (method.ReturnType == typeof(void)) { return method.Invoke(Target, args);//直接返回 } else { var result = method.Invoke(Target, args); return result;//返回结果 } } } /// /// 异步无返回值 /// /// /// /// /// public override async Task InvokeAsync(MethodInfo method, object[] args) { var desc = method.GetActualCustomAttribute(Target); if (desc == null) { var task = method.Invoke(Target, args) as Task; await task; } else { Exception exception = default; try { var task = method.Invoke(Target, args) as Task; await task; } catch (Exception ex) { exception = ex; } WriteOperLog(method, args, desc, null, exception); if (exception != null) { throw exception; } } } /// /// 异步带返回值 /// /// /// /// /// /// public override async Task InvokeAsyncT(MethodInfo method, object[] args) { var desc = method.GetActualCustomAttribute(Target); if (desc == null) { var taskT = method.Invoke(Target, args) as Task; var result = await taskT; return result;//返回结果 } else { T result = default; //写入操作日志 Exception exception = null; try { var taskT = method.Invoke(Target, args) as Task; result = await taskT; } catch (Exception ex) { exception = ex; } WriteOperLog(method, args, desc, result, exception); if (exception != null) { throw exception; } else { return result;//返回结果 } } } private static void WriteOperLog(MethodInfo method, object[] args, OperDescAttribute desc, object result, Exception exception) { //写入操作日志 var str = App.HttpContext?.Request?.Headers?.UserAgent; ClientInfo clientInfo = null; if (str.HasValue) { clientInfo = StaticParser.Parser.Parse(str); } StringBuilder stringBuilder = new(); if (desc.IsRecordPar) { var parameters = method.GetParameters(); var jsonParameters = parameters.Select((p, i) => $"\"{p.Name}\": {args[i].ToJsonString()}"); stringBuilder.Append("{"); stringBuilder.Append(string.Join(", ", jsonParameters)); stringBuilder.Append("}"); } var paramJson = stringBuilder.ToString(); var resultJson = desc.IsRecordPar ? result?.ToJsonString() : null; //操作日志表实体 var log = new SysOperateLog { Name = desc.Description, Category = desc.Catcategory, ExeStatus = LogConst.LOG_SUCCESS, OpIp = App.HttpContext?.Connection?.RemoteIpAddress?.MapToIPv4().ToString(), OpBrowser = clientInfo?.UA?.Family + clientInfo?.UA?.Major, OpOs = clientInfo?.OS?.Family + clientInfo?.OS?.Major, OpTime = SysDateTimeExtensions.CurrentDateTime, OpAccount = UserManager.UserAccount, ReqUrl = "", ReqMethod = LogConst.LOG_REQMETHOD, ResultJson = resultJson, ClassName = method.ReflectedType.Name, MethodName = method.Name, ParamJson = paramJson, VerificatId = UserManager.VerificatId.ToLong(), }; //如果异常不为空 if (exception != null) { log.ExeStatus = LogConst.LOG_FAIL;//操作状态为失败 log.ExeMessage = exception.Source + ":" + exception.Message + Environment.NewLine + exception.StackTrace; } DbContext.Db.InsertableWithAttr(log).ExecuteCommand();//入库 } }