/// <summary> /// Proceeds the able. /// </summary> /// <param name="invocation">Invocation.</param> private void ProceedAble(IInvocation invocation, CachingAbleAttribute attribute) { var serviceMethod = invocation.Method ?? invocation.MethodInvocationTarget; var returnType = serviceMethod.IsReturnTask() ? serviceMethod.ReturnType.GetGenericArguments().First() : serviceMethod.ReturnType; var cacheKey = string.IsNullOrEmpty(attribute.CacheKey) ? _keyGenerator.GetCacheKey(serviceMethod, invocation.Arguments, attribute.CacheKeyPrefix) : attribute.CacheKey ; object cacheValue = null; var isAvailable = true; try { cacheValue = _cacheProvider.GetAsync(cacheKey, returnType).GetAwaiter().GetResult(); } catch (Exception ex) { if (!attribute.IsHighAvailability) { throw; } else { isAvailable = false; _logger?.LogError(new EventId(), ex, $"Cache provider get error."); } } if (cacheValue != null) { if (serviceMethod.IsReturnTask()) { invocation.ReturnValue = TypeofTaskResultMethod.GetOrAdd(returnType, t => typeof(Task).GetMethods().First(p => p.Name == "FromResult" && p.ContainsGenericParameters).MakeGenericMethod(returnType)).Invoke(null, new object[] { cacheValue }); } else { invocation.ReturnValue = cacheValue; } } else { // Invoke the method if we don't have a cache hit invocation.Proceed(); if (!string.IsNullOrWhiteSpace(cacheKey) && invocation.ReturnValue != null && isAvailable) { // get the result var returnValue = serviceMethod.IsReturnTask() ? invocation.UnwrapAsyncReturnValue().Result : invocation.ReturnValue; // should we do something when method return null? // 1. cached a null value for a short time // 2. do nothing if (returnValue != null) { _cacheProvider.Set(cacheKey, returnValue, TimeSpan.FromSeconds(attribute.Expiration)); } } } }
private void InternalInterceptSynchronous(IInvocation invocation, CachingInterceptorAttribute attribute) { var methodInfo = invocation.Method ?? invocation.MethodInvocationTarget; if (attribute is CachingAbleAttribute ableAttribute) { var cacheKey = string.IsNullOrEmpty(attribute.CacheKey) ? _keyGenerator.GetCacheKey(methodInfo, invocation.Arguments, attribute.CacheKeyPrefix) : attribute.CacheKey ; try { var cacheValue = _cacheProvider.GetAsync(cacheKey, methodInfo.ReturnType).GetAwaiter().GetResult(); if (cacheKey != null) { invocation.ReturnValue = cacheValue; } else { invocation.Proceed(); if (!string.IsNullOrWhiteSpace(cacheKey) && invocation.ReturnValue != null) { _cacheProvider.Set(cacheKey, invocation.ReturnValue, TimeSpan.FromSeconds(ableAttribute.Expiration)); } } } catch (Exception ex) { if (!attribute.IsHighAvailability) { throw; } else { _logger?.LogError(new EventId(), ex, $"Cache provider get error."); } } return; } if (attribute is CachingEvictAttribute evictAttribute) { var(cacheKeys, expireDt) = ProcessEvictBefore(invocation, evictAttribute); var cancelTokenSource = new CancellationTokenSource(); var timeoutPolicy = Policy.Timeout(_cacheProvider.CacheOptions.PollyTimeoutSeconds, Polly.Timeout.TimeoutStrategy.Optimistic); try { timeoutPolicy.Execute((cancellToken) => { invocation.Proceed(); cancellToken.ThrowIfCancellationRequested(); }, cancelTokenSource.Token); _cacheProvider.RemoveAll(cacheKeys); } catch (Exception ex) { LocalVariables.Instance.Queue.Enqueue(new LocalVariables.Model(cacheKeys, expireDt)); if (!attribute.IsHighAvailability) { throw; } else { _logger?.LogError(new EventId(), ex, $"Cache provider remove error."); } } } }