之前有写实现Memory缓存的。异曲同工之妙。
使用Redis离不开安装get包:StackExchange.Redis.
操作流程:
public class RedisAOP : IInterceptor { protected readonly IRedisCaching redis; public RedisAOP(IRedisCaching _redis) { this.redis = _redis; } public void Intercept(IInvocation invocation) { var method = invocation.MethodInvocationTarget ?? invocation.Method; //获取自定义缓存键 var cacheKey = CustomCacheKey(invocation); //根据key获取相应的缓存值 var cacheValue = redis.GetValue(cacheKey).Result; if (cacheValue != null) { //动态返回类型 Type returnType; //获取传入方法的返回类型。如果是多个就取默认第一个 if (typeof(Task).IsAssignableFrom(method.ReturnType)) { returnType = method.ReturnType.GenericTypeArguments.FirstOrDefault(); } else { returnType = method.ReturnType; } //将数据解析成方法返回类型 dynamic _result = JsonSerializer.Deserialize(cacheValue, returnType); invocation.ReturnValue = (typeof(Task).IsAssignableFrom(method.ReturnType)) ? Task.FromResult(_result) : _result; return; } //去执行当前的方法 invocation.Proceed(); //存入缓存 if (!string.IsNullOrWhiteSpace(cacheKey)) { redis.Set(cacheKey, invocation.ReturnValue,TimeSpan.FromHours(24)); } } /// <summary> /// object 转 string /// </summary> /// <param name="arg"></param> /// <returns></returns> protected 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.GetType().IsClass) { return MD5Helper.MD5Encrypt16(JsonSerializer.Serialize(arg)); } } return string.Empty; } /// <summary> /// 自定义缓存的key /// </summary> /// <param name="invocation"></param> /// <returns></returns> protected string CustomCacheKey(IInvocation invocation) { var typeName = invocation.TargetType.Name; var methodName = invocation.Method.Name; var methodArguments = invocation.Arguments.Select(GetArgumentValue).Take(3).ToList();//获取参数列表,最多三个 string key = $"{typeName}:{methodName}:"; foreach (var param in methodArguments) { key = $"{key}{param}:"; } return key.TrimEnd(':'); } }
public class RedisCaching : IRedisCaching { private readonly ConnectionMultiplexer redis; private readonly IDatabase database; public RedisCaching(ConnectionMultiplexer _redis) { this.redis = _redis; database = _redis.GetDatabase(); } /// <summary> /// 获取值 /// </summary> /// <param name="key"></param> /// <returns></returns> public async Task<string> GetValue(string key) { return await database.StringGetAsync(key); } /// <summary> /// 存储值 /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <param name="cacheTime">过期时间</param> /// <returns></returns> /// <exception cref="NotImplementedException"></exception> public async Task Set(string key, object value, TimeSpan cacheTime) { if (value != null) { if (value is string cacheValue) { // 字符串无需序列化 await database.StringSetAsync(key, cacheValue, cacheTime); } else { //序列化,将object值生成RedisValue await database.StringSetAsync(key, JsonSerializer.Serialize(value), cacheTime); } } } }
//接口 builder.Services.AddSingleton<IRedisCaching,RedisCaching>(); //Redis builder.Services.AddSingleton<ConnectionMultiplexer>(sp => { //获取连接字符串 string redisConfiguration = "127.0.0.1:6678,password=123456"; var configuration = ConfigurationOptions.Parse(redisConfiguration, true); configuration.ResolveDns = true; return ConnectionMultiplexer.Connect(configuration); });
var assemblysServicesPath = Path.Combine(basePath, "DogService"); builder.RegisterType<LogAOP>();//可以直接替换其他拦截器!一定要把拦截器进行注册 builder.RegisterType<RedisAOP>(); //注入仓储 var assemblysRepository = Assembly.LoadFrom(assemblysRepositoryPath); builder.RegisterAssemblyTypes(assemblysRepository) .AsImplementedInterfaces()//方法表示将组件以其实现的接口类型进行注册,这样在进行依赖注入时,可以根据接口类型获取相应的实现类 .PropertiesAutowired()//方法用于自动装配属性依赖 .InstancePerDependency()//方法表示每次请求时都创建一个新的实例。 .EnableInterfaceInterceptors()//方法启用接口拦截,使得后续可以对注册的接口进行拦截。 .InterceptedBy(typeof(LogAOP),typeof(RedisAOP));//表
完活!