平安校园
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

422 linhas
16 KiB

  1. //
  2. namespace SafeCampus.Plugin.Aop;
  3. /// <summary>
  4. /// Aop
  5. /// 这里没有继承IGlobalDispatchProxy是因为IGlobalDispatchProxy会把一些没有必要的方法也aop了
  6. /// </summary>
  7. public class GlobalDispatchProxy : AspectDispatchProxy, IDispatchProxy
  8. {
  9. /// <summary>
  10. /// 当前服务实例
  11. /// </summary>
  12. public object Target { get; set; }
  13. /// <summary>
  14. /// 服务提供器,可以用来解析服务,如:Services.GetService()
  15. /// </summary>
  16. public IServiceProvider Services { get; set; }
  17. /// <summary>
  18. /// 方法
  19. /// </summary>
  20. /// <param name="method"></param>
  21. /// <param name="args"></param>
  22. /// <returns></returns>
  23. /// <exception cref="NotImplementedException"></exception>
  24. public override object Invoke(MethodInfo method, object[] args)
  25. {
  26. //如果不带返回值
  27. if (method.ReturnType == typeof(void))
  28. {
  29. After(method, null, args);
  30. return method.Invoke(Target, args);//直接返回
  31. }
  32. var result = Before(method, args);//方法执行之前判断是否有缓存的数据
  33. if (result == null) result = method.Invoke(Target, args);//如果没有缓存就执行方法返回数据
  34. After(method, result, args);//方法执行之后干的事
  35. return result;//返回结果
  36. }
  37. /// <summary>
  38. /// 异步无返回值
  39. /// </summary>
  40. /// <param name="method"></param>
  41. /// <param name="args"></param>
  42. /// <returns></returns>
  43. /// <exception cref="NotImplementedException"></exception>
  44. public override async Task InvokeAsync(MethodInfo method, object[] args)
  45. {
  46. var task = method.Invoke(Target, args) as Task;
  47. await task;
  48. After(method, null, args);
  49. }
  50. /// <summary>
  51. /// 异步带返回值
  52. /// </summary>
  53. /// <typeparam name="T"></typeparam>
  54. /// <param name="method"></param>
  55. /// <param name="args"></param>
  56. /// <returns></returns>
  57. /// <exception cref="NotImplementedException"></exception>
  58. public override async Task<T> InvokeAsyncT<T>(MethodInfo method, object[] args)
  59. {
  60. var result = Before(method, args);//方法执行之前判断是否有缓存的数据
  61. if (result == null)
  62. {
  63. var taskT = method.Invoke(Target, args) as Task<T>;
  64. result = await taskT;//如果没有缓存就执行方法返回数据
  65. }
  66. After(method, result, args);//方法执行之后干的事
  67. return result;//返回结果
  68. }
  69. /// <summary>
  70. /// 方法执行之后
  71. /// </summary>
  72. /// <param name="method">方法</param>
  73. /// <param name="returnValue">返回值</param>
  74. /// <param name="args">参数列表</param>
  75. private void After(MethodInfo method, object returnValue, object[] args)
  76. {
  77. RecordCache(method, args, returnValue);//记录返回值到缓存
  78. }
  79. /// <summary>
  80. /// 方法执行之前
  81. /// </summary>
  82. /// <param name="method">方法</param>
  83. /// <param name="args">参数列表</param>
  84. /// <returns></returns>
  85. private dynamic Before(MethodInfo method, object[] args)
  86. {
  87. var cacheData = CheckCache(method, args);//检查缓存
  88. if (cacheData != null) { return cacheData; }//如果缓存有数据直接返回
  89. return null;//默认返回空
  90. }
  91. /// <summary>
  92. /// 检查缓存里是否有数据
  93. /// </summary>
  94. /// <param name="method">方法</param>
  95. /// <param name="args">参数列表</param>
  96. private dynamic CheckCache(MethodInfo method, object[] args)
  97. {
  98. var cacheAttribute = method.GetActualCustomAttribute<CacheAttribute>(Target);//读取缓存特性
  99. //判断需不需要读取缓存
  100. if (cacheAttribute != null)
  101. {
  102. var redisManager = Services.GetService<ISimpleCacheService>();// 获取redis服务
  103. var cacheKey = cacheAttribute.CustomKeyValue
  104. ?? CustomCacheKey(cacheAttribute.KeyPrefix, method, args);//如果redisKey值,如果有自定义值就用自定义Key,否则以前缀+系统自动生成的Key
  105. string cacheValue;
  106. if (cacheAttribute.StoreType == CacheConst.CACHE_HASH)//如果存的是Hash值
  107. {
  108. cacheValue = redisManager.HashGet<string>(cacheKey, args[0].ToString())[0];//从redis获取Hash数据取第一个,注意是 string 类型
  109. }
  110. else
  111. {
  112. cacheValue = redisManager.Get<string>(cacheKey);//注意是 string 类型,方法GetValue
  113. }
  114. if (!string.IsNullOrEmpty(cacheValue))//如果返回值不是空
  115. {
  116. //if (cacheAttribute.IsDelete)//判断是否是删除操作
  117. //{
  118. // if (cacheAttribute.StoreType == RedisConst.Cache_Hash)//如果是Hash
  119. // {
  120. // _redisManager.HashDel<string>(cacheKey, new string[] { args[0].ToString() });
  121. // }
  122. // else
  123. // {
  124. // //删除Redis整个KEY
  125. // _redisManager.Remove(cacheKey);
  126. // }
  127. //}
  128. //将当前获取到的缓存值,赋值给当前执行方法
  129. Type returnType;
  130. if (typeof(Task).IsAssignableFrom(method.ReturnType))
  131. {
  132. returnType = method.ReturnType.GenericTypeArguments.FirstOrDefault();
  133. }
  134. else
  135. {
  136. returnType = method.ReturnType;
  137. }
  138. if (!returnType.IsPrimitive && returnType != typeof(string))//判断返回类型是否原生类型并且不是string
  139. {
  140. dynamic result = JsonConvert.DeserializeObject(cacheValue, returnType);//序列化数据
  141. return result;
  142. }
  143. return cacheValue;
  144. }
  145. }
  146. return null;
  147. }
  148. /// <summary>
  149. /// 写数据到缓存
  150. /// </summary>
  151. /// <param name="method">方法</param>
  152. /// <param name="args">参数列表</param>
  153. /// <param name="returnValue">返回值</param>
  154. private void RecordCache(MethodInfo method, object[] args, object returnValue)
  155. {
  156. var cacheAttribute = method.GetActualCustomAttribute<CacheAttribute>(Target);
  157. if (cacheAttribute != null)
  158. {
  159. //获取自定义缓存键
  160. var cacheKey = cacheAttribute.CustomKeyValue ?? CustomCacheKey(cacheAttribute.KeyPrefix, method, args);
  161. if (!string.IsNullOrWhiteSpace(cacheKey))//如果有key
  162. {
  163. var redisManager = Services.GetService<ISimpleCacheService>();// 获取redis服务
  164. if (cacheAttribute.IsDelete)//判断是否是删除操作
  165. {
  166. //删除Redis整个KEY
  167. redisManager.Remove(cacheKey);
  168. }
  169. else
  170. {
  171. if (returnValue == null) { return; }
  172. if (cacheAttribute.StoreType == CacheConst.CACHE_HASH)//如果是hash类型的
  173. {
  174. //插入到hash,这里规定是方法的第一个参数
  175. redisManager.HashAdd(cacheKey, args[0].ToString(), returnValue);
  176. }
  177. else
  178. {
  179. if (cacheAttribute.AbsoluteExpiration != null)//如果有超时时间
  180. {
  181. redisManager.Set(cacheKey, returnValue, cacheAttribute.AbsoluteExpiration.Value);//插入redis
  182. }
  183. else
  184. {
  185. redisManager.Set(cacheKey, returnValue);//插入redis
  186. }
  187. }
  188. }
  189. }
  190. }
  191. }
  192. /// <summary>
  193. /// 自定义缓存Key
  194. /// </summary>
  195. /// <param name="prefix">前缀</param>
  196. /// <param name="method">方法</param>
  197. /// <param name="args">参数</param>
  198. /// <returns></returns>
  199. protected string CustomCacheKey(string prefix, MethodInfo method, object[] args)
  200. {
  201. var key = prefix;//前缀
  202. var methodArguments = args.Select(GetCacheKey.GetArgumentValue).Take(3).ToList();//获取参数列表,最多三个
  203. if (!string.IsNullOrEmpty(key))//如果制定了前缀
  204. {
  205. foreach (var param in methodArguments)//遍历参数列表
  206. {
  207. key = $"{key}{param}:";//生成KEY
  208. }
  209. }
  210. else
  211. {
  212. var typeName = Target.GetType().Name;//获取实例名
  213. var methodName = method.Name;//获取方法名
  214. key = $"{CacheConst.CACHE_PREFIX_WEB}{typeName}:{methodName}:";//生成Key
  215. foreach (var param in methodArguments)//遍历参数列表
  216. {
  217. key = $"{key}{param}:";//生成加上参数的KEY
  218. }
  219. }
  220. return key.TrimEnd(':');
  221. }
  222. }
  223. /// <summary>
  224. /// 获取缓存Key
  225. /// </summary>
  226. internal static class GetCacheKey
  227. {
  228. /// <summary>
  229. /// object 转 string
  230. /// </summary>
  231. /// <param name="arg"></param>
  232. /// <returns></returns>
  233. public static string GetArgumentValue(object arg)
  234. {
  235. if (arg is DateTime || arg is DateTime)
  236. return ((DateTime)arg).ToString("yyyyMMddHHmmss");
  237. if (arg is string || arg is ValueType || arg is Nullable)
  238. return arg.ToString();
  239. if (arg != null)
  240. {
  241. if (arg is Expression)
  242. {
  243. var obj = arg as Expression;
  244. var result = Resolve(obj);
  245. return MD5Encryption.Encrypt(result);
  246. }
  247. if (arg.GetType().IsClass)
  248. {
  249. return MD5Encryption.Encrypt(JsonConvert.SerializeObject(arg));
  250. }
  251. }
  252. return string.Empty;
  253. }
  254. private static string Resolve(Expression expression)
  255. {
  256. if (expression is LambdaExpression)
  257. {
  258. var lambda = expression as LambdaExpression;
  259. expression = lambda.Body;
  260. return Resolve(expression);
  261. }
  262. if (expression is BinaryExpression)
  263. {
  264. var binary = expression as BinaryExpression;
  265. if (binary.Left is MemberExpression && binary.Right is ConstantExpression)//解析x=>x.Name=="123" x.Age==123这类
  266. return ResolveFunc(binary.Left, binary.Right, binary.NodeType);
  267. if (binary.Left is MethodCallExpression && binary.Right is ConstantExpression)//解析x=>x.Name.Contains("xxx")==false这类的
  268. {
  269. var value = (binary.Right as ConstantExpression).Value;
  270. return ResolveLinqToObject(binary.Left, value, binary.NodeType);
  271. }
  272. if (binary.Left is MemberExpression && binary.Right is MemberExpression
  273. || binary.Left is MemberExpression && binary.Right is UnaryExpression)//解析x=>x.Date==DateTime.Now这种
  274. {
  275. var lambda = Expression.Lambda(binary.Right);
  276. var fn = lambda.Compile();
  277. var value = Expression.Constant(fn.DynamicInvoke(null), binary.Right.Type);
  278. return ResolveFunc(binary.Left, value, binary.NodeType);
  279. }
  280. }
  281. if (expression is UnaryExpression)
  282. {
  283. var unary = expression as UnaryExpression;
  284. if (unary.Operand is MethodCallExpression)//解析!x=>x.Name.Contains("xxx")或!array.Contains(x.Name)这类
  285. return ResolveLinqToObject(unary.Operand, false);
  286. if (unary.Operand is MemberExpression && unary.NodeType == ExpressionType.Not)//解析x=>!x.isDeletion这样的
  287. {
  288. var constant = Expression.Constant(false);
  289. return ResolveFunc(unary.Operand, constant, ExpressionType.Equal);
  290. }
  291. }
  292. if (expression is MemberExpression && expression.NodeType == ExpressionType.MemberAccess)//解析x=>x.isDeletion这样的
  293. {
  294. var member = expression as MemberExpression;
  295. var constant = Expression.Constant(true);
  296. return ResolveFunc(member, constant, ExpressionType.Equal);
  297. }
  298. if (expression is MethodCallExpression)//x=>x.Name.Contains("xxx")或array.Contains(x.Name)这类
  299. {
  300. var methodcall = expression as MethodCallExpression;
  301. return ResolveLinqToObject(methodcall, true);
  302. }
  303. //已经修改过代码body应该不会是null值了
  304. if (!(expression is BinaryExpression body))
  305. return string.Empty;
  306. var @operator = GetOperator(body.NodeType);
  307. var left = Resolve(body.Left);
  308. var right = Resolve(body.Right);
  309. var result = string.Format("({0} {1} {2})", left, @operator, right);
  310. return result;
  311. }
  312. private static string ResolveFunc(Expression left, Expression right, ExpressionType expressiontype)
  313. {
  314. var name = (left as MemberExpression).Member.Name;
  315. var value = (right as ConstantExpression).Value;
  316. var @operator = GetOperator(expressiontype);
  317. return name + @operator + value;
  318. }
  319. private static string ResolveLinqToObject(Expression expression, object value, ExpressionType? expressiontype = null)
  320. {
  321. var methodCall = expression as MethodCallExpression;
  322. var methodName = methodCall.Method.Name;
  323. switch (methodName)
  324. {
  325. case "Contains":
  326. return methodCall.Object != null ? Like(methodCall) : In(methodCall, value);
  327. case "Count":
  328. return Len(methodCall, value, expressiontype.Value);
  329. case "LongCount":
  330. return Len(methodCall, value, expressiontype.Value);
  331. default:
  332. throw new Exception(string.Format("不支持{0}方法的查找!", methodName));
  333. }
  334. }
  335. private static string GetOperator(ExpressionType expressiontype)
  336. {
  337. return expressiontype switch
  338. {
  339. ExpressionType.And => "and",
  340. ExpressionType.AndAlso => "and",
  341. ExpressionType.Or => "or",
  342. ExpressionType.OrElse => "or",
  343. ExpressionType.Equal => "=",
  344. ExpressionType.NotEqual => "<>",
  345. ExpressionType.LessThan => "<",
  346. ExpressionType.LessThanOrEqual => "<=",
  347. ExpressionType.GreaterThan => ">",
  348. ExpressionType.GreaterThanOrEqual => ">=",
  349. _ => throw new Exception(string.Format("不支持{0}此种运算符查找!" + expressiontype))
  350. };
  351. }
  352. private static string In(MethodCallExpression expression, object isTrue)
  353. {
  354. var argument1 = (expression.Arguments[0] as MemberExpression).Expression as ConstantExpression;
  355. var argument2 = expression.Arguments[1] as MemberExpression;
  356. var fieldArray = argument1.Value.GetType().GetFields().First();
  357. var array = fieldArray.GetValue(argument1.Value) as object[];
  358. var setInPara = new List<string>();
  359. for (var i = 0; i < array.Length; i++)
  360. {
  361. var value = array[i].ToString();
  362. setInPara.Add(value);
  363. }
  364. var name = argument2.Member.Name;
  365. var @operator = Convert.ToBoolean(isTrue) ? "in" : " not in";
  366. var compName = string.Join(",", setInPara);
  367. var result = string.Format("{0} {1} ({2})", name, @operator, compName);
  368. return result;
  369. }
  370. private static string Like(MethodCallExpression expression)
  371. {
  372. var temp = expression.Arguments[0];
  373. var lambda = Expression.Lambda(temp);
  374. var fn = lambda.Compile();
  375. var tempValue = Expression.Constant(fn.DynamicInvoke(null), temp.Type);
  376. var value = string.Format("%{0}%", tempValue);
  377. var name = (expression.Object as MemberExpression).Member.Name;
  378. var result = string.Format("{0} like {1}", name, value);
  379. return result;
  380. }
  381. private static string Len(MethodCallExpression expression, object value, ExpressionType expressiontype)
  382. {
  383. object name = (expression.Arguments[0] as MemberExpression).Member.Name;
  384. var @operator = GetOperator(expressiontype);
  385. var result = string.Format("len({0}){1}{2}", name, @operator, value);
  386. return result;
  387. }
  388. }