/// <summary> /// Processes the evict async. /// </summary> /// <returns>The evict async.</returns> /// <param name="context">Context.</param> /// <param name="isBefore">If set to <c>true</c> is before.</param> private async Task ProcessEvictAsync(AspectContext context, bool isBefore) { if (GetMethodAttributes(context.ServiceMethod).FirstOrDefault(x => x.GetType() == typeof(EasyCachingEvictAttribute)) is EasyCachingEvictAttribute attribute && attribute.IsBefore == isBefore) { var _cacheProvider = CacheProviderFactory.GetCachingProvider(attribute.CacheProviderName ?? Options.Value.CacheProviderName); try { if (attribute.IsAll) { //If is all , clear all cached items which cachekey start with the prefix. var cachePrefix = KeyGenerator.GetCacheKeyPrefix(context.ServiceMethod, attribute.CacheKeyPrefix); await _cacheProvider.RemoveByPrefixAsync(cachePrefix); } else { //If not all , just remove the cached item by its cachekey. var cacheKey = KeyGenerator.GetCacheKey(context.ServiceMethod, context.Parameters, attribute.CacheKeyPrefix); await _cacheProvider.RemoveAsync(cacheKey); } } catch (Exception ex) { if (!attribute.IsHightAvailability) { throw; } else { Logger?.LogError(new EventId(), ex, $"Cache provider \"{_cacheProvider.Name}\" remove error."); } } } }
/// <summary> /// Processes the put async. /// </summary> /// <returns>The put async.</returns> /// <param name="context">Context.</param> private async Task ProcessPutAsync(AspectContext context) { if (GetMethodAttributes(context.ServiceMethod).FirstOrDefault(x => x.GetType() == typeof(EasyCachingPutAttribute)) is EasyCachingPutAttribute attribute && context.ReturnValue != null) { var _cacheProvider = CacheProviderFactory.GetCachingProvider(attribute.CacheProviderName ?? Options.Value.CacheProviderName); var cacheKey = KeyGenerator.GetCacheKey(context.ServiceMethod, context.Parameters, attribute.CacheKeyPrefix); try { if (context.IsAsync()) { //get the result var returnValue = await context.UnwrapAsyncReturnValue(); await _cacheProvider.SetAsync(cacheKey, returnValue, TimeSpan.FromSeconds(attribute.Expiration)); } else { await _cacheProvider.SetAsync(cacheKey, context.ReturnValue, TimeSpan.FromSeconds(attribute.Expiration)); } } catch (Exception ex) { if (!attribute.IsHightAvailability) { throw; } else { Logger?.LogError(new EventId(), ex, $"Cache provider \"{_cacheProvider.Name}\" set error."); } } } }
/// <summary> /// Invoke the specified context and next. /// </summary> /// <returns>The invoke.</returns> /// <param name="context">Context.</param> /// <param name="next">Next.</param> public async override Task Invoke(AspectContext context, AspectDelegate next) { _cacheProvider = _cacheProvider ?? CacheProviderFactory.GetCachingProvider(Options.Value.CacheProviderName); //Process any early evictions await ProcessEvictAsync(context, true); //Process any cache interceptor await ProceedAbleAsync(context, next); // Process any put requests await ProcessPutAsync(context); // Process any late evictions await ProcessEvictAsync(context, false); }
/// <summary> /// Proceeds the able async. /// </summary> /// <returns>The able async.</returns> /// <param name="context">Context.</param> /// <param name="next">Next.</param> private async Task ProceedAbleAsync(AspectContext context, AspectDelegate next) { if (GetMethodAttributes(context.ServiceMethod).FirstOrDefault(x => typeof(EasyCachingAbleAttribute).IsAssignableFrom(x.GetType())) is EasyCachingAbleAttribute attribute) { var returnType = context.IsAsync() ? context.ServiceMethod.ReturnType.GetGenericArguments().First() : context.ServiceMethod.ReturnType; var cacheKey = KeyGenerator.GetCacheKey(context.ServiceMethod, context.Parameters, attribute.CacheKeyPrefix); object cacheValue = null; var isAvailable = true; try { if (attribute.IsHybridProvider) { cacheValue = await HybridCachingProvider.GetAsync(cacheKey, returnType); } else { var _cacheProvider = CacheProviderFactory.GetCachingProvider(attribute.CacheProviderName ?? Options.Value.CacheProviderName); cacheValue = await _cacheProvider.GetAsync(cacheKey, returnType); } } catch (Exception ex) { if (!attribute.IsHighAvailability) { throw; } else { isAvailable = false; Logger?.LogError(new EventId(), ex, $"Cache provider get error."); } } if (cacheValue != null) { if (context.IsAsync()) { //#1 //dynamic member = context.ServiceMethod.ReturnType.GetMember("Result")[0]; //dynamic temp = System.Convert.ChangeType(cacheValue.Value, member.PropertyType); //context.ReturnValue = System.Convert.ChangeType(Task.FromResult(temp), context.ServiceMethod.ReturnType); //#2 context.ReturnValue = TypeofTaskResultMethod.GetOrAdd(returnType, t => typeof(Task).GetMethods().First(p => p.Name == "FromResult" && p.ContainsGenericParameters).MakeGenericMethod(returnType)).Invoke(null, new object[] { cacheValue }); } else { //context.ReturnValue = System.Convert.ChangeType(cacheValue.Value, context.ServiceMethod.ReturnType); context.ReturnValue = cacheValue; } } else { // Invoke the method if we don't have a cache hit await next(context); if (isAvailable) { // get the result var returnValue = context.IsAsync() ? await context.UnwrapAsyncReturnValue() : context.ReturnValue; // should we do something when method return null? // 1. cached a null value for a short time // 2. do nothing if (returnValue != null) { if (attribute.IsHybridProvider) { await HybridCachingProvider.SetAsync(cacheKey, returnValue, TimeSpan.FromSeconds(attribute.Expiration)); } else { var _cacheProvider = CacheProviderFactory.GetCachingProvider(attribute.CacheProviderName ?? Options.Value.CacheProviderName); await _cacheProvider.SetAsync(cacheKey, returnValue, TimeSpan.FromSeconds(attribute.Expiration)); } } } } } else { // Invoke the method if we don't have EasyCachingAbleAttribute await next(context); } }
/// <summary> /// /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <returns></returns> private async Task ProcessRedisCaching(AspectContext context, AspectDelegate next) { var attribute = GetMethodAttributes(context.ServiceMethod).FirstOrDefault(x => x.GetType() == typeof(RedisCachingAttribute)) as RedisCachingAttribute; if (attribute == null) { await context.Invoke(next); } var returnType = context.IsAsync() ? context.ServiceMethod.ReturnType.GetGenericArguments().First() : context.ServiceMethod.ReturnType; var cacheKey = ""; cacheKey = KeyGenerator.GetCacheKey(context.ServiceMethod, context.Parameters, attribute.CacheKeyPrefix); if (context.Parameters != null && context.Parameters.Length > 0) { var md5key = Encrypt.Md5By32(Json.ToJson(context.Parameters)); cacheKey = cacheKey + ":" + md5key; } else { var md5key = Encrypt.Md5By32(Json.ToJson(context.ServiceMethod.Name)); cacheKey = cacheKey + ":" + md5key; } object cacheValue = null; var isAvailable = true; try { if (attribute.IsHybridProvider) { cacheValue = await HybridCachingProvider.GetAsync(cacheKey, returnType); } else { var _cacheProvider = CacheProviderFactory.GetCachingProvider(attribute.CacheProviderName ?? Options.Value.CacheProviderName); //cacheValue = await _cacheProvider.GetAsync(cacheKey, returnType); var val = await _cacheProvider.GetAsync <string>(cacheKey); if (val.HasValue) { cacheValue = JsonConvert.DeserializeObject(val.Value, returnType); } } } catch (Exception ex) { if (!attribute.IsHighAvailability) { throw ex; } else { isAvailable = false; } } if (cacheValue != null) { if (context.IsAsync()) { //#1 //dynamic member = context.ServiceMethod.ReturnType.GetMember("Result")[0]; //dynamic temp = System.Convert.ChangeType(cacheValue.Value, member.PropertyType); //context.ReturnValue = System.Convert.ChangeType(Task.FromResult(temp), context.ServiceMethod.ReturnType); //#2 context.ReturnValue = TypeofTaskResultMethod.GetOrAdd(returnType, t => typeof(Task).GetMethods().First(p => p.Name == "FromResult" && p.ContainsGenericParameters).MakeGenericMethod(returnType)).Invoke(null, new object[] { cacheValue }); } else { //context.ReturnValue = System.Convert.ChangeType(cacheValue.Value, context.ServiceMethod.ReturnType); context.ReturnValue = cacheValue; } return; } // Invoke the method if we don't have a cache hit await next(context); try { if (isAvailable) { // get the result var returnValue = context.IsAsync() ? await context.UnwrapAsyncReturnValue() : context.ReturnValue; // should we do something when method return null? // 1. cached a null value for a short time // 2. do nothing if (returnValue != null && cacheKey.IsNotWhiteSpaceEmpty()) { if (attribute.IsHybridProvider) { await HybridCachingProvider.SetAsync(cacheKey, returnValue, TimeSpan.FromSeconds(attribute.Expiration)); } else { var _cacheProvider = CacheProviderFactory.GetCachingProvider(attribute.CacheProviderName ?? Options.Value.CacheProviderName); //var f = Newtonsoft.Json.JsonConvert.SerializeObject(returnValue); await _cacheProvider.SetAsync(cacheKey, JsonConvert.SerializeObject(returnValue, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, DateTimeZoneHandling = DateTimeZoneHandling.Local }), TimeSpan.FromSeconds(attribute.Expiration)); } } } } catch (Exception ex) { ex.Submit(); } }