|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 |
-
- //
-
-
-
-
-
-
-
-
- namespace SafeCampus.Plugin.Aop;
-
- /// <summary>
- /// Aop
- /// 这里没有继承IGlobalDispatchProxy是因为IGlobalDispatchProxy会把一些没有必要的方法也aop了
- /// </summary>
- public class GlobalDispatchProxy : AspectDispatchProxy, IDispatchProxy
- {
- /// <summary>
- /// 当前服务实例
- /// </summary>
- public object Target { get; set; }
-
- /// <summary>
- /// 服务提供器,可以用来解析服务,如:Services.GetService()
- /// </summary>
- public IServiceProvider Services { get; set; }
-
- /// <summary>
- /// 方法
- /// </summary>
- /// <param name="method"></param>
- /// <param name="args"></param>
- /// <returns></returns>
- /// <exception cref="NotImplementedException"></exception>
- 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;//返回结果
- }
-
- /// <summary>
- /// 异步无返回值
- /// </summary>
- /// <param name="method"></param>
- /// <param name="args"></param>
- /// <returns></returns>
- /// <exception cref="NotImplementedException"></exception>
- public override async Task InvokeAsync(MethodInfo method, object[] args)
- {
- var task = method.Invoke(Target, args) as Task;
- await task;
- After(method, null, args);
- }
-
- /// <summary>
- /// 异步带返回值
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="method"></param>
- /// <param name="args"></param>
- /// <returns></returns>
- /// <exception cref="NotImplementedException"></exception>
- public override async Task<T> InvokeAsyncT<T>(MethodInfo method, object[] args)
- {
- var result = Before(method, args);//方法执行之前判断是否有缓存的数据
- if (result == null)
- {
- var taskT = method.Invoke(Target, args) as Task<T>;
- result = await taskT;//如果没有缓存就执行方法返回数据
- }
- After(method, result, args);//方法执行之后干的事
- return result;//返回结果
- }
-
- /// <summary>
- /// 方法执行之后
- /// </summary>
- /// <param name="method">方法</param>
- /// <param name="returnValue">返回值</param>
- /// <param name="args">参数列表</param>
- private void After(MethodInfo method, object returnValue, object[] args)
- {
- RecordCache(method, args, returnValue);//记录返回值到缓存
- }
-
- /// <summary>
- /// 方法执行之前
- /// </summary>
- /// <param name="method">方法</param>
- /// <param name="args">参数列表</param>
- /// <returns></returns>
- private dynamic Before(MethodInfo method, object[] args)
- {
- var cacheData = CheckCache(method, args);//检查缓存
- if (cacheData != null) { return cacheData; }//如果缓存有数据直接返回
- return null;//默认返回空
- }
-
- /// <summary>
- /// 检查缓存里是否有数据
- /// </summary>
- /// <param name="method">方法</param>
- /// <param name="args">参数列表</param>
- private dynamic CheckCache(MethodInfo method, object[] args)
- {
- var cacheAttribute = method.GetActualCustomAttribute<CacheAttribute>(Target);//读取缓存特性
- //判断需不需要读取缓存
- if (cacheAttribute != null)
- {
- var redisManager = Services.GetService<ISimpleCacheService>();// 获取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<string>(cacheKey, args[0].ToString())[0];//从redis获取Hash数据取第一个,注意是 string 类型
- }
- else
- {
- cacheValue = redisManager.Get<string>(cacheKey);//注意是 string 类型,方法GetValue
- }
- if (!string.IsNullOrEmpty(cacheValue))//如果返回值不是空
- {
- //if (cacheAttribute.IsDelete)//判断是否是删除操作
- //{
- // if (cacheAttribute.StoreType == RedisConst.Cache_Hash)//如果是Hash
- // {
- // _redisManager.HashDel<string>(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;
- }
-
- /// <summary>
- /// 写数据到缓存
- /// </summary>
- /// <param name="method">方法</param>
- /// <param name="args">参数列表</param>
- /// <param name="returnValue">返回值</param>
- private void RecordCache(MethodInfo method, object[] args, object returnValue)
- {
- var cacheAttribute = method.GetActualCustomAttribute<CacheAttribute>(Target);
- if (cacheAttribute != null)
- {
- //获取自定义缓存键
- var cacheKey = cacheAttribute.CustomKeyValue ?? CustomCacheKey(cacheAttribute.KeyPrefix, method, args);
- if (!string.IsNullOrWhiteSpace(cacheKey))//如果有key
- {
- var redisManager = Services.GetService<ISimpleCacheService>();// 获取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
- }
- }
- }
- }
- }
- }
-
- /// <summary>
- /// 自定义缓存Key
- /// </summary>
- /// <param name="prefix">前缀</param>
- /// <param name="method">方法</param>
- /// <param name="args">参数</param>
- /// <returns></returns>
- 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(':');
- }
- }
-
- /// <summary>
- /// 获取缓存Key
- /// </summary>
- internal static class GetCacheKey
- {
- /// <summary>
- /// object 转 string
- /// </summary>
- /// <param name="arg"></param>
- /// <returns></returns>
- 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<string>();
- 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;
- }
- }
|