Esempio n. 1
0
        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            var logger = LogManager.GetLogger("ProxyInterceptor");

            var parameters = JsonConvert.SerializeObject(context.Parameters);

            logger.Info($"Call api {context.ServiceMethod.DeclaringType.FullName}->{context.ServiceMethod.Name} Paramters:{parameters}");

            await next(context);

            if (context.IsAsync())
            {
                if (context.ServiceMethod.ReturnType.FullName == "System.Threading.Tasks.Task")
                {
                    logger.Info($"Result value: void");
                }
                else
                {
                    var result = await context.UnwrapAsyncReturnValue();

                    var res = JsonConvert.SerializeObject(result);
                    logger.Info($"Result value: {res}");
                }
            }
            else
            {
                if (context.ReturnValue != null)
                {
                    var res = JsonConvert.SerializeObject(context.ReturnValue);
                    logger.Info($"Result value: {res}");
                }
            }
        }
        public async override Task Invoke(AspectContext context, AspectDelegate next)
        {
            var Parameters = context.Parameters;
            await context.Invoke(next);

            var result = context.IsAsync() ? await context.UnwrapAsyncReturnValue(): context.ReturnValue;
        }
        /// <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.");
                    }
                }
            }
        }
Esempio n. 4
0
        /// <summary>
        /// 执行被拦截方法
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        private async Task <object> RunAndGetReturn(AspectContext context, AspectDelegate next)
        {
            await context.Invoke(next);

            return(context.IsAsync()
            ? await context.UnwrapAsyncReturnValue()
            : context.ReturnValue);
        }
Esempio n. 5
0
        public async override Task Invoke(AspectContext context, AspectDelegate next)
        {
            Assert.True(context.IsAsync());
            await context.Invoke(next);

            var result = context.UnwrapAsyncReturnValue();

            Assert.Equal(100, result);
        }
        private async Task ProcessGetOrCreateAsync(AspectContext context, AspectDelegate next)
        {
            if (GetMethodAttributes(context.ServiceMethod) is EniymCacheGetOrCreateAttribute attribute)
            {
                if (string.IsNullOrEmpty(attribute.Template))
                {
                    throw new ArgumentNullException($"please set the cache key '{nameof(attribute.Template)}'");
                }

                var returnType = context.IsAsync()
                    ? context.ServiceMethod.ReturnType.GetGenericArguments().First()
                    : context.ServiceMethod.ReturnType;

                var cacheKey = KeyGenerator.GetCacheKey(context, attribute.Template);
                Logger.LogInformation($"KeyGenerator.GetCacheKey: '{cacheKey}'");

                object cacheValue = null;
                try
                {
                    cacheValue = await CacheProvider.GetAsync(cacheKey, returnType);
                }
                catch
                {
                    Logger.LogError($"An error occurred while reading cache '{cacheKey}'.");
                    cacheValue = null;
                }

                if (cacheValue != null)
                {
                    context.ReturnValue = context.IsAsync()
                        ? TaskResultMethod
                                          .GetOrAdd(returnType,
                                                    t => typeof(Task).GetMethods()
                                                    .First(p => p.Name == "FromResult" && p.ContainsGenericParameters)
                                                    .MakeGenericMethod(returnType)).Invoke(null, new object[] { cacheValue })
                        : cacheValue;
                }
                else
                {
                    await next(context);

                    var returnValue = context.IsAsync()
                        ? await context.UnwrapAsyncReturnValue()
                        : context.ReturnValue;

                    if (returnValue != null)
                    {
                        await CacheProvider.SetAsync(cacheKey, returnValue, attribute.CacheSeconds);
                    }
                }
            }
            else
            {
                await next(context);
            }
        }
Esempio n. 7
0
        /// <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 (context.ServiceMethod.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(EasyCachingAbleAttribute)) 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 = await CacheProvider.GetAsync(cacheKey, returnType);

                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 (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));
                    }
                }
            }
            else
            {
                // Invoke the method if we don't have EasyCachingAbleAttribute
                await next(context);
            }
        }
        private async Task DoCaching(
            AspectContext context,
            AspectDelegate next,
            CachingAttribute cachingAttribute
            )
        {
            var cacheProvider = context.ServiceProvider.GetService(typeof(ICachingProvider)) as ICachingProvider;

            var    cachingKey = GenerateCachingKey(context, cachingAttribute);
            object cacheValue = await cacheProvider.GetAsync <object>(cachingKey);

            if (cacheValue != null)// 若读取到缓存就直接返回,否则设置缓存
            {
                if (context.IsAsync())
                {
                    PropertyInfo propertyInfo = context.ServiceMethod.ReturnType.GetMember("Result")[0] as PropertyInfo;
                    dynamic      returnValue  = JsonConvert.DeserializeObject(cacheValue.ToString(), propertyInfo.PropertyType);

                    context.ReturnValue = Task.FromResult(returnValue);
                }
                else
                {
                    context.ReturnValue = JsonConvert.DeserializeObject(cacheValue.ToString(), context.ServiceMethod.ReturnType);
                }
            }
            else
            {
                await next(context);

                // 设置缓存
                if (!string.IsNullOrWhiteSpace(cachingKey))
                {
                    object returnValue = null;

                    if (context.IsAsync())
                    {
                        returnValue = await context.UnwrapAsyncReturnValue();
                    }
                    else
                    {
                        returnValue = context.ReturnValue;
                    }

                    await cacheProvider.SetAsync(
                        cachingKey,
                        returnValue,
                        TimeSpan.FromSeconds(cachingAttribute.Expiration)
                        );
                }
            }
        }
Esempio n. 9
0
        /// <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)
        {
            var attribute = context.ServiceMethod.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(EasyCachingAbleAttribute)) as EasyCachingAbleAttribute;

            if (attribute != null)
            {
                var cacheKey   = KeyGenerator.GetCacheKey(context.ServiceMethod, context.Parameters, attribute.CacheKeyPrefix);
                var cacheValue = await CacheProvider.GetAsync <object>(cacheKey);

                if (cacheValue.HasValue)
                {
                    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
                        //...
                    }
                    else
                    {
                        context.ReturnValue = System.Convert.ChangeType(cacheValue.Value, context.ServiceMethod.ReturnType);
                    }
                }
                else
                {
                    // Invoke the method if we don't have a cache hit
                    await next(context);

                    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));
                    }
                }
            }
            else
            {
                // Invoke the method if we don't have EasyCachingAbleAttribute
                await next(context);
            }
        }
Esempio n. 10
0
        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            var logger = LogManager.GetLogger("ProxyInterceptor");

            var parameters = JsonConvert.SerializeObject(context.Parameters);

            logger.Info($"Call api {context.ServiceMethod.DeclaringType.FullName}->{context.ServiceMethod.Name} Paramters:{parameters}");

            await next(context);

            var res = JsonConvert.SerializeObject(await context.UnwrapAsyncReturnValue());

            logger.Info($"Result value: {res}");
        }
Esempio n. 11
0
            public override async Task Invoke(AspectContext context, AspectDelegate next)
            {
                if (context.Proxy is Service service)
                {
                    service.CurrentValue = null;
                    await context.Invoke(next);

                    var value = await context.UnwrapAsyncReturnValue();

                    service.CurrentValue = value;
                }
                else
                {
                    await context.Invoke(next);
                }
            }
        /// <summary>
        /// 执行后
        /// </summary>
        /// <param name="log">日志操作</param>
        /// <param name="context">Aspect上下文</param>
        /// <param name="methodName">方法名</param>
        private async Task ExecuteAfter(ILog log, AspectContext context, string methodName)
        {
            if (context.ServiceMethod.ReturnType == typeof(Task) ||
                context.ServiceMethod.ReturnType == typeof(void) ||
                context.ServiceMethod.ReturnType == typeof(ValueTask))
            {
                return;
            }
            var returnValue = context.IsAsync() ? await context.UnwrapAsyncReturnValue() : context.ReturnValue;

            var returnType = returnValue.GetType().FullName;

            log.Caption($"{context.ServiceMethod.Name}方法执行后")
            .Method(methodName)
            .Content($"返回类型: {returnType}, 返回值: {returnValue.SafeString()}");
            WriteLog(log);
        }
        /// <summary>
        /// Processes the put async.
        /// </summary>
        /// <returns>The put async.</returns>
        /// <param name="context">Context.</param>
        private async Task ProcessPutAsync(AspectContext context)
        {
            if (context.ServiceMethod.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(EasyCachingPutAttribute)) is EasyCachingPutAttribute attribute && context.ReturnValue != null)
            {
                var cacheKey = KeyGenerator.GetCacheKey(context.ServiceMethod, context.Parameters, attribute.CacheKeyPrefix);

                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));
                }
            }
        }
Esempio n. 14
0
 private object buildResult(AspectContext context)
 {
     return(context.IsAsync() ? context.UnwrapAsyncReturnValue().Result : context.ReturnValue);
 }
 public static async Task <object> GetReturnValue(this AspectContext context)
 {
     return(context.IsAsync() ? await context.UnwrapAsyncReturnValue() : context.ReturnValue);
 }
Esempio n. 16
0
        public async override Task Invoke(AspectContext context, AspectDelegate next)
        {
            var returnType = context.GetReturnParameter().Type;
            var hasCache   = context.ImplementationMethod.GetCustomAttributes(typeof(CacheAttribute), false).Any();

            if (returnType == typeof(void) ||
                returnType == typeof(Task) ||
                returnType == typeof(ValueTask) ||
                !hasCache)
            {
                await next(context);

                return;
            }

            if (context.IsAsync())
            {
                returnType = returnType.GenericTypeArguments.FirstOrDefault();
            }

            var cacheKey = this.CreateCacheKey(context);

            this.Log("trying to get", cacheKey);

            var cacheService = (ICacheService)context.ServiceProvider.GetService(typeof(ICacheService));

            var cachedResult = cacheService.Get(cacheKey);

            if (cachedResult == null)
            {
                this.Log("key not found", cacheKey);
                await next(context);

                var returnValue = context.IsAsync()
                    ? await context.UnwrapAsyncReturnValue()
                    : context.ReturnValue;

                this.Log("trying to set", cacheKey);
                if (!cacheService.Set(cacheKey, returnValue))
                {
                    this.Log("failed to set", cacheKey);
                }
            }
            else
            {
                this.Log("found key", cacheKey);
                if (context.IsAsync())
                {
                    if (context.ImplementationMethod.ReturnType == typeof(Task <>).MakeGenericType(returnType))
                    {
                        context.ReturnValue = typeof(Task)
                                              .GetMethod(nameof(Task.FromResult))
                                              .MakeGenericMethod(returnType)
                                              .Invoke(null, new[] { cachedResult });
                    }
                    if (context.ImplementationMethod.ReturnType == typeof(ValueTask <>).MakeGenericType(returnType))
                    {
                        context.ReturnValue = Activator
                                              .CreateInstance(typeof(ValueTask <>).MakeGenericType(returnType), cachedResult);
                    }
                }
                else
                {
                    context.ReturnValue = cachedResult;
                }
            }
        }
        /// <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();
            }
        }
 public async static Task <object> GetReturnValueAsync(this AspectContext context)
 => context.IsAsync() ?
 await context.UnwrapAsyncReturnValue() :
 context.ReturnValue;
Esempio n. 19
0
        /// <summary>
        /// 执行
        /// </summary>
        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            List <string> appendKeyArray = null;

            if (string.IsNullOrWhiteSpace(Key))
            {
                Key =
                    $"{context.ServiceMethod.DeclaringType}.{context.ImplementationMethod.Name}:{context.ServiceMethod.ToString()}";
            }
            else
            {
                if (!AppendKeyParameters.TryGetValue(context.ImplementationMethod, out appendKeyArray))
                {
                    if (Key.IndexOf("{", StringComparison.Ordinal) > -1)
                    {
                        appendKeyArray = new List <string>();
                        var matchs = Regex.Matches(Key, @"\{\w*\:?\w*\}", RegexOptions.None);
                        foreach (Match match in matchs)
                        {
                            if (match.Success)
                            {
                                appendKeyArray.Add(match.Value.TrimStart('{').TrimEnd('}'));
                            }
                        }
                    }

                    AppendKeyParameters.TryAdd(context.ImplementationMethod, appendKeyArray);
                }
            }

            var currentCacheKey = Key;

            if (appendKeyArray != null && appendKeyArray.Count > 0)
            {
                // 获取方法的参数
                var pars = context.ProxyMethod.GetParameters();

                // 设置参数名和值,加入字典
                var dicValue = new Dictionary <string, object>();
                for (var i = 0; i < pars.Length; i++)
                {
                    dicValue.Add(pars[i].Name, context.Parameters[i]);
                }

                foreach (var key in appendKeyArray)
                {
                    if (key.Contains(":"))
                    {
                        var arr       = key.Split(':');
                        var keyFirst  = arr[0];
                        var keySecond = arr[1];

                        if (!dicValue.TryGetValue(keyFirst, out var value))
                        {
                            throw new Warning(
                                      $"Cache {context.ServiceMethod.DeclaringType}.{context.ImplementationMethod.Name} 不包含参数 {keyFirst}");
                        }

                        var ob = Internal.Helper.ToDictionary(value);
                        if (!ob.TryGetValue(keySecond, out object tokenValue))
                        {
                            throw new Warning(
                                      $"Cache {context.ServiceMethod.DeclaringType}.{context.ImplementationMethod.Name} {keyFirst} 不包含参数 {keySecond}");
                        }

                        currentCacheKey = currentCacheKey.Replace("{" + key + "}", tokenValue.ToString());
                    }
                    else
                    {
                        if (!dicValue.TryGetValue(key, out var value))
                        {
                            throw new Warning(
                                      $"Cache {context.ServiceMethod.DeclaringType}.{context.ImplementationMethod.Name} 不包含参数 {key}");
                        }

                        currentCacheKey = currentCacheKey.Replace("{" + key + "}", value.ToString());
                    }
                }
            }

            // 返回值类型
            var returnType = context.IsAsync()
                ? context.ServiceMethod.ReturnType.GetGenericArguments().First()
                : context.ServiceMethod.ReturnType;

            // 从缓存取值
            var cacheValue = await Cache.GetAsync(currentCacheKey, returnType);

            if (cacheValue != null)
            {
                context.ReturnValue = context.IsAsync()
                    ? TaskResultMethod.MakeGenericMethod(returnType).Invoke(null, new object[] { cacheValue })
                    : cacheValue;
                return;
            }

            using (await _lock.LockAsync())
            {
                cacheValue = await Cache.GetAsync(currentCacheKey, returnType);

                if (cacheValue != null)
                {
                    context.ReturnValue = context.IsAsync()
                        ? TaskResultMethod.MakeGenericMethod(returnType).Invoke(null, new object[] { cacheValue })
                        : cacheValue;
                }
                else
                {
                    await next(context);

                    dynamic returnValue =
                        context.IsAsync() ? await context.UnwrapAsyncReturnValue() : context.ReturnValue;

                    Cache.TryAdd(currentCacheKey, returnValue, Expiration);
                }
            }
        }
Esempio n. 20
0
        /// <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);
            }
        }