// namespace SafeCampus.Plugin.Aop; /// /// Aop /// 这里没有继承IGlobalDispatchProxy是因为IGlobalDispatchProxy会把一些没有必要的方法也aop了 /// public class GlobalDispatchProxy : AspectDispatchProxy, IDispatchProxy { /// /// 当前服务实例 /// public object Target { get; set; } /// /// 服务提供器,可以用来解析服务,如:Services.GetService() /// public IServiceProvider Services { get; set; } /// /// 方法 /// /// /// /// /// public override object Invoke(MethodInfo method, object[] args) { //如果不带返回值 if (method.ReturnType == typeof(void)) { After(method, null, args); return method.Invoke(Target, args);//直接返回 } var result = Before(method, args);//方法执行之前判断是否有缓存的数据 if (result == null) result = method.Invoke(Target, args);//如果没有缓存就执行方法返回数据 After(method, result, args);//方法执行之后干的事 return result;//返回结果 } /// /// 异步无返回值 /// /// /// /// /// public override async Task InvokeAsync(MethodInfo method, object[] args) { var task = method.Invoke(Target, args) as Task; await task; After(method, null, args); } /// /// 异步带返回值 /// /// /// /// /// /// public override async Task InvokeAsyncT(MethodInfo method, object[] args) { var result = Before(method, args);//方法执行之前判断是否有缓存的数据 if (result == null) { var taskT = method.Invoke(Target, args) as Task; result = await taskT;//如果没有缓存就执行方法返回数据 } After(method, result, args);//方法执行之后干的事 return result;//返回结果 } /// /// 方法执行之后 /// /// 方法 /// 返回值 /// 参数列表 private void After(MethodInfo method, object returnValue, object[] args) { RecordCache(method, args, returnValue);//记录返回值到缓存 } /// /// 方法执行之前 /// /// 方法 /// 参数列表 /// private dynamic Before(MethodInfo method, object[] args) { var cacheData = CheckCache(method, args);//检查缓存 if (cacheData != null) { return cacheData; }//如果缓存有数据直接返回 return null;//默认返回空 } /// /// 检查缓存里是否有数据 /// /// 方法 /// 参数列表 private dynamic CheckCache(MethodInfo method, object[] args) { var cacheAttribute = method.GetActualCustomAttribute(Target);//读取缓存特性 //判断需不需要读取缓存 if (cacheAttribute != null) { var redisManager = Services.GetService();// 获取redis服务 var cacheKey = cacheAttribute.CustomKeyValue ?? CustomCacheKey(cacheAttribute.KeyPrefix, method, args);//如果redisKey值,如果有自定义值就用自定义Key,否则以前缀+系统自动生成的Key string cacheValue; if (cacheAttribute.StoreType == CacheConst.CACHE_HASH)//如果存的是Hash值 { cacheValue = redisManager.HashGet(cacheKey, args[0].ToString())[0];//从redis获取Hash数据取第一个,注意是 string 类型 } else { cacheValue = redisManager.Get(cacheKey);//注意是 string 类型,方法GetValue } if (!string.IsNullOrEmpty(cacheValue))//如果返回值不是空 { //if (cacheAttribute.IsDelete)//判断是否是删除操作 //{ // if (cacheAttribute.StoreType == RedisConst.Cache_Hash)//如果是Hash // { // _redisManager.HashDel(cacheKey, new string[] { args[0].ToString() }); // } // else // { // //删除Redis整个KEY // _redisManager.Remove(cacheKey); // } //} //将当前获取到的缓存值,赋值给当前执行方法 Type returnType; if (typeof(Task).IsAssignableFrom(method.ReturnType)) { returnType = method.ReturnType.GenericTypeArguments.FirstOrDefault(); } else { returnType = method.ReturnType; } if (!returnType.IsPrimitive && returnType != typeof(string))//判断返回类型是否原生类型并且不是string { dynamic result = JsonConvert.DeserializeObject(cacheValue, returnType);//序列化数据 return result; } return cacheValue; } } return null; } /// /// 写数据到缓存 /// /// 方法 /// 参数列表 /// 返回值 private void RecordCache(MethodInfo method, object[] args, object returnValue) { var cacheAttribute = method.GetActualCustomAttribute(Target); if (cacheAttribute != null) { //获取自定义缓存键 var cacheKey = cacheAttribute.CustomKeyValue ?? CustomCacheKey(cacheAttribute.KeyPrefix, method, args); if (!string.IsNullOrWhiteSpace(cacheKey))//如果有key { var redisManager = Services.GetService();// 获取redis服务 if (cacheAttribute.IsDelete)//判断是否是删除操作 { //删除Redis整个KEY redisManager.Remove(cacheKey); } else { if (returnValue == null) { return; } if (cacheAttribute.StoreType == CacheConst.CACHE_HASH)//如果是hash类型的 { //插入到hash,这里规定是方法的第一个参数 redisManager.HashAdd(cacheKey, args[0].ToString(), returnValue); } else { if (cacheAttribute.AbsoluteExpiration != null)//如果有超时时间 { redisManager.Set(cacheKey, returnValue, cacheAttribute.AbsoluteExpiration.Value);//插入redis } else { redisManager.Set(cacheKey, returnValue);//插入redis } } } } } } /// /// 自定义缓存Key /// /// 前缀 /// 方法 /// 参数 /// protected string CustomCacheKey(string prefix, MethodInfo method, object[] args) { var key = prefix;//前缀 var methodArguments = args.Select(GetCacheKey.GetArgumentValue).Take(3).ToList();//获取参数列表,最多三个 if (!string.IsNullOrEmpty(key))//如果制定了前缀 { foreach (var param in methodArguments)//遍历参数列表 { key = $"{key}{param}:";//生成KEY } } else { var typeName = Target.GetType().Name;//获取实例名 var methodName = method.Name;//获取方法名 key = $"{CacheConst.CACHE_PREFIX_WEB}{typeName}:{methodName}:";//生成Key foreach (var param in methodArguments)//遍历参数列表 { key = $"{key}{param}:";//生成加上参数的KEY } } return key.TrimEnd(':'); } } /// /// 获取缓存Key /// internal static class GetCacheKey { /// /// object 转 string /// /// /// public static string GetArgumentValue(object arg) { if (arg is DateTime || arg is DateTime) return ((DateTime)arg).ToString("yyyyMMddHHmmss"); if (arg is string || arg is ValueType || arg is Nullable) return arg.ToString(); if (arg != null) { if (arg is Expression) { var obj = arg as Expression; var result = Resolve(obj); return MD5Encryption.Encrypt(result); } if (arg.GetType().IsClass) { return MD5Encryption.Encrypt(JsonConvert.SerializeObject(arg)); } } return string.Empty; } private static string Resolve(Expression expression) { if (expression is LambdaExpression) { var lambda = expression as LambdaExpression; expression = lambda.Body; return Resolve(expression); } if (expression is BinaryExpression) { var binary = expression as BinaryExpression; if (binary.Left is MemberExpression && binary.Right is ConstantExpression)//解析x=>x.Name=="123" x.Age==123这类 return ResolveFunc(binary.Left, binary.Right, binary.NodeType); if (binary.Left is MethodCallExpression && binary.Right is ConstantExpression)//解析x=>x.Name.Contains("xxx")==false这类的 { var value = (binary.Right as ConstantExpression).Value; return ResolveLinqToObject(binary.Left, value, binary.NodeType); } if (binary.Left is MemberExpression && binary.Right is MemberExpression || binary.Left is MemberExpression && binary.Right is UnaryExpression)//解析x=>x.Date==DateTime.Now这种 { var lambda = Expression.Lambda(binary.Right); var fn = lambda.Compile(); var value = Expression.Constant(fn.DynamicInvoke(null), binary.Right.Type); return ResolveFunc(binary.Left, value, binary.NodeType); } } if (expression is UnaryExpression) { var unary = expression as UnaryExpression; if (unary.Operand is MethodCallExpression)//解析!x=>x.Name.Contains("xxx")或!array.Contains(x.Name)这类 return ResolveLinqToObject(unary.Operand, false); if (unary.Operand is MemberExpression && unary.NodeType == ExpressionType.Not)//解析x=>!x.isDeletion这样的 { var constant = Expression.Constant(false); return ResolveFunc(unary.Operand, constant, ExpressionType.Equal); } } if (expression is MemberExpression && expression.NodeType == ExpressionType.MemberAccess)//解析x=>x.isDeletion这样的 { var member = expression as MemberExpression; var constant = Expression.Constant(true); return ResolveFunc(member, constant, ExpressionType.Equal); } if (expression is MethodCallExpression)//x=>x.Name.Contains("xxx")或array.Contains(x.Name)这类 { var methodcall = expression as MethodCallExpression; return ResolveLinqToObject(methodcall, true); } //已经修改过代码body应该不会是null值了 if (!(expression is BinaryExpression body)) return string.Empty; var @operator = GetOperator(body.NodeType); var left = Resolve(body.Left); var right = Resolve(body.Right); var result = string.Format("({0} {1} {2})", left, @operator, right); return result; } private static string ResolveFunc(Expression left, Expression right, ExpressionType expressiontype) { var name = (left as MemberExpression).Member.Name; var value = (right as ConstantExpression).Value; var @operator = GetOperator(expressiontype); return name + @operator + value; } private static string ResolveLinqToObject(Expression expression, object value, ExpressionType? expressiontype = null) { var methodCall = expression as MethodCallExpression; var methodName = methodCall.Method.Name; switch (methodName) { case "Contains": return methodCall.Object != null ? Like(methodCall) : In(methodCall, value); case "Count": return Len(methodCall, value, expressiontype.Value); case "LongCount": return Len(methodCall, value, expressiontype.Value); default: throw new Exception(string.Format("不支持{0}方法的查找!", methodName)); } } private static string GetOperator(ExpressionType expressiontype) { return expressiontype switch { ExpressionType.And => "and", ExpressionType.AndAlso => "and", ExpressionType.Or => "or", ExpressionType.OrElse => "or", ExpressionType.Equal => "=", ExpressionType.NotEqual => "<>", ExpressionType.LessThan => "<", ExpressionType.LessThanOrEqual => "<=", ExpressionType.GreaterThan => ">", ExpressionType.GreaterThanOrEqual => ">=", _ => throw new Exception(string.Format("不支持{0}此种运算符查找!" + expressiontype)) }; } private static string In(MethodCallExpression expression, object isTrue) { var argument1 = (expression.Arguments[0] as MemberExpression).Expression as ConstantExpression; var argument2 = expression.Arguments[1] as MemberExpression; var fieldArray = argument1.Value.GetType().GetFields().First(); var array = fieldArray.GetValue(argument1.Value) as object[]; var setInPara = new List(); for (var i = 0; i < array.Length; i++) { var value = array[i].ToString(); setInPara.Add(value); } var name = argument2.Member.Name; var @operator = Convert.ToBoolean(isTrue) ? "in" : " not in"; var compName = string.Join(",", setInPara); var result = string.Format("{0} {1} ({2})", name, @operator, compName); return result; } private static string Like(MethodCallExpression expression) { var temp = expression.Arguments[0]; var lambda = Expression.Lambda(temp); var fn = lambda.Compile(); var tempValue = Expression.Constant(fn.DynamicInvoke(null), temp.Type); var value = string.Format("%{0}%", tempValue); var name = (expression.Object as MemberExpression).Member.Name; var result = string.Format("{0} like {1}", name, value); return result; } private static string Len(MethodCallExpression expression, object value, ExpressionType expressiontype) { object name = (expression.Arguments[0] as MemberExpression).Member.Name; var @operator = GetOperator(expressiontype); var result = string.Format("len({0}){1}{2}", name, @operator, value); return result; } }