namespace CloudGaming.Core.Redis.Aop.Cache; [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] public abstract class BaseCacheAttribute : AopMoAttribute { /// /// 缓存Key 不填默认是 函数的命名空间.函数名称 /// /// public string? CacheKey { get; set; } /// /// Redis 服务类型 不传递默认 走内存缓存 /// /// public Type RedisServiceType { get; set; } = null!; /// /// 获取缓存Key /// /// /// protected virtual string GetCacheKey(MethodContext context) { if (!string.IsNullOrWhiteSpace(CacheKey)) { return ParseCacheKey(context); } var name = context.Method.Name; var prefix = context.Method.DeclaringType?.FullName; return $"{prefix}.{name}"; } /// /// 解析缓存主键 /// /// 拦截器上下文 private string ParseCacheKey(MethodContext context) { //寻找大括号{} 内的内容 var replaceParameters = Regex.Matches(CacheKey, @"\{(.+?)\}").Select(m => m.Groups[1].Value).ToList(); if (replaceParameters.Count > 0) { // 获取所有方法参数 var typeNames = context.Method.GetParameters().Select(t => t.Name).ToList(); foreach (var replaceParameter in replaceParameters) { var firstName = replaceParameter.Split(".")[0]; // 查询括号里的内容 .分割后第一位 能和参数名对的上吗 if (typeNames.Contains(firstName)) { // 获取这个值对应的索引 int index = typeNames.FindIndex(tname => tname == firstName); // 对内容进行分割 var names = replaceParameter.Split(".").ToList(); // 分割后大于长度大于一 说明存在实例内部属性调用 if (names.Count > 1) { var replaceName = "{" + replaceParameter + "}"; // 移除第一位 names.RemoveAt(0); // 递归获取到属性值 var value = GetParameterValue(context.Arguments[index], names); value = value ?? "null"; CacheKey = CacheKey.Replace(replaceName, value); } else { var replaceName = "{" + replaceParameter + "}"; var value = context.Arguments[index]?.ToString(); CacheKey = CacheKey.Replace(replaceName, value); } } } } return CacheKey; } /// /// 递归获取属性值 /// /// /// /// private string GetParameterValue(object obj, List parameterNames) { if (obj == null) { return null; } if (parameterNames.Count > 1) { var name = parameterNames[0]; parameterNames.RemoveAt(0); // 获取属性值 var propertyInfo = GetPropertyInfo(obj, name); if (propertyInfo != null) { return GetParameterValue(propertyInfo.GetValue(obj), parameterNames); } return null; } else if (parameterNames.Count == 1) { // 获取属性值 var propertyInfo = GetPropertyInfo(obj, parameterNames[0]); // 从对象里获取这个属性 return propertyInfo?.GetValue(obj)?.ToString(); } else { return null; } } /// /// 根据属性名称获取实例里的属性 /// /// 实例 /// 需要的属性名 /// private PropertyInfo GetPropertyInfo(object obj, string name) { if (obj == null) { return null; } // 获取所有public属性和实例 var propertyInfos = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); // 找找有没有我们要的 return propertyInfos.FirstOrDefault(p => p.Name == name); } /// /// 获取Redis数据库 /// /// /// protected IDatabase GetDatabase(MethodContext MethodContext) { var redisService = this.GetService(MethodContext, RedisServiceType); if (redisService == null) { throw new Exception($"Redis服务 {RedisServiceType.FullName} 找不到属性 public IDatabase {nameof(IDatabase.Database)} {{get;}}"); } var propertyInfos = redisService.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); var databasePropertyInfo = propertyInfos.FirstOrDefault(w => w.Name == nameof(IDatabase.Database) && w.PropertyType == typeof(IDatabase)); if (databasePropertyInfo == null) { throw new Exception($"Redis服务 {RedisServiceType.FullName} 找不到属性 public IDatabase {nameof(IDatabase.Database)} {{get;}}"); } // 获取 idatabase var redisCache = (IDatabase?)databasePropertyInfo.GetValue(redisService); if (redisCache == null) { throw new Exception($"Redis服务 {RedisServiceType.FullName} 属性 public IDatabase {nameof(IDatabase.Database)} {{get;}} 是 null "); } return redisCache; } }