张建平 发表于 2024-9-5 01:28:32

.net8 AOP 实现简单的Json Redis 缓存/业务分离

 场景: 在不动 业务逻辑的情况下, 实现读写缓存
   这里使用的AOP的方式 在 方法上加注解, 这目前有个弊端不能传数组, 涉及到排序问题
/// <summary>
/// Json Redis缓存
/// </summary>
public class RedisInterceptorAttribute : AbstractInterceptorAttribute
{
      readonly string _cacheKey;
      bool _isDb = false; //是否走缓存
      int _expireSeconds = -1;
   

      public RedisInterceptorAttribute(string cacheKey, int expireSeconds = -1,bool isDb=false)
      {
          _cacheKey = cacheKey;
          _isDb = isDb;
          _expireSeconds = expireSeconds;
      }

      public override async Task Invoke(AspectContext context, AspectDelegate next)
      {
         
          Type returnType = context.ServiceMethod.ReturnType;
          Type genericArgument = returnType.GetGenericArguments();
          // 生成缓存的key
          string cacheKeyWithParams = GenerateCacheKey(context);

          if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
          {
            //通过类型获取缓存方法,并且调用 GetAsync 方法
            MethodInfo method = this.GetType().GetMethod("GetAsync", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
            MethodInfo genericMethod = method.MakeGenericMethod(genericArgument);

            var cacheTask = (Task)genericMethod.Invoke(this, new object[] { cacheKeyWithParams });
            await cacheTask.ConfigureAwait(true);

            var resultProperty = cacheTask.GetType().GetProperty("Result");
            var cacheResult = resultProperty.GetValue(cacheTask);


            if (cacheResult != null)
            {
                  context.ReturnValue = ConvertToReturnType(cacheResult, returnType);
                  // 设置缓存的逻辑
                  await Task.CompletedTask;

            }
            else
            {
                  await context.Invoke(next);
                  // 设置缓存
                   if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
                  {
                      MethodInfo setMethod = this.GetType().GetMethod("SetAsync", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
                      MethodInfo genericSetMethod = setMethod.MakeGenericMethod(genericArgument);

                      var resultProperty1 = context.ReturnValue.GetType().GetProperty("Result");
                      var result = resultProperty1.GetValue(context.ReturnValue);
                      await (Task)genericSetMethod.Invoke(this, new object[] { cacheKeyWithParams, result });
                  }
            }
          }
          else
          {
            await next(context);
          }
      }
      private string GenerateCacheKey(AspectContext context)
      {
          var keyBuilder = new System.Text.StringBuilder(_cacheKey);

          foreach (var parameter in context.Parameters)
          {
            keyBuilder.Append(":").Append(FormatParameter(parameter));
          }

          return keyBuilder.ToString();
      }

      /// <summary>
      /// 格式化参数(类似url过滤一下数据,: 会影响阅读)
      /// </summary>
      /// <param name="parameter"></param>
      /// <returns></returns>
      private string FormatParameter(object parameter)
      {
         
          return JsonConvert.SerializeObject(parameter).Replace(":", "=").Replace("{", "").Replace("}", "").Replace("\"", "").Replace(",", "&");
      }
      /// <summary>
      /// 将返回值转换为原有类型
      /// </summary>
      /// <param name="result"></param>
      /// <param name="returnType"></param>
      /// <returns></returns>
      private object ConvertToReturnType(object result, Type returnType)
      {
          Type taskResultType = returnType.GetGenericArguments();
          return typeof(Task).GetMethod(nameof(Task.FromResult))
                           .MakeGenericMethod(taskResultType)
                           .Invoke(null, new[] { result });
      }

      async Task<T> GetAsync<T>(string key)
      {
          var result = await RedisHelper.GetAsync<T>(key);
          return result;
      }

      async Task SetAsync<T>(string cacheKey, T data)
      {
          if (data != null)
          {
            await RedisHelper.SetAsync(cacheKey, data, _expireSeconds);
          }
      }

}这样就简单实现了
只需要在方法上加注解, 一定要加virtual
   //一定要加virtual
   
   public virtual async Task<List<string>> SelectAsync(Guid[] schoolId)
   {
         ///业务
         return new();
   }QQ群: 929412850 (Byte.Core 框架交流群)
未经作者同意,禁止转发
   

来源:https://www.cnblogs.com/wxhwpmdyz/p/18397527
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: .net8 AOP 实现简单的Json Redis 缓存/业务分离