public abstract Task Invoke(AspectDelegate next);
/// <summary> /// 拦截器 /// </summary> /// <param name="aspectContext">拦截上下文</param> /// <param name="_next">下一个拦截器 最后一个是执行被拦截的方法</param> /// <returns></returns> public abstract Task OnInvocation(AspectContext aspectContext, AspectDelegate _next);
public async override Task Invoke(AspectContext context, AspectDelegate next) { CacheAbleAttribute attribute = context.GetAttribute <CacheAbleAttribute>(); if (attribute == null) { await context.Invoke(next); return; } try { Database = RedisClient.GetDatabase(); string cacheKey = KeyGenerator.GetCacheKey(context.ServiceMethod, context.Parameters, attribute.CacheKeyPrefix); string cacheValue = await GetCacheAsync(cacheKey); Type returnType = context.GetReturnType(); if (string.IsNullOrWhiteSpace(cacheValue)) { if (attribute.OnceUpdate) { string lockKey = $"Lock_{cacheKey}"; RedisValue token = Environment.MachineName; if (await Database.LockTakeAsync(lockKey, token, TimeSpan.FromSeconds(10))) { try { var result = await RunAndGetReturn(context, next); await SetCache(cacheKey, result, attribute.Expiration); return; } finally { await Database.LockReleaseAsync(lockKey, token); } } else { for (int i = 0; i < 5; i++) { Thread.Sleep(i * 100 + 500); cacheValue = await GetCacheAsync(cacheKey); if (!string.IsNullOrWhiteSpace(cacheValue)) { break; } } if (string.IsNullOrWhiteSpace(cacheValue)) { var defaultValue = CreateDefaultResult(returnType); context.ReturnValue = ResultFactory(defaultValue, returnType, context.IsAsync()); return; } } } else { var result = await RunAndGetReturn(context, next); await SetCache(cacheKey, result, attribute.Expiration); return; } } var objValue = await DeserializeCache(cacheKey, cacheValue, returnType); //缓存值不可用 if (objValue == null) { await context.Invoke(next); return; } context.ReturnValue = ResultFactory(objValue, returnType, context.IsAsync()); } catch (Exception) { if (context.ReturnValue == null) { await context.Invoke(next); } } }
public override Task Invoke(AspectContext context, AspectDelegate next) { context.Parameters[0] = FakeProperty?.Val; return(context.Invoke(next)); }
public abstract Task Handle(AspectContext context, AspectDelegate next);
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; } } }
public Task Invoke(AspectContext context, AspectDelegate next) { return(_aspectDelegate(next)(context)); }
public override Task Invoke(AspectContext context, AspectDelegate next) { context.Parameters[0] = "lemon"; return(context.Invoke(next)); }
public override async Task Invoke(AspectContext context, AspectDelegate next) { //一个HystrixCommand中保持一个policy对象即可 //其实主要是CircuitBreaker要求对于同一段代码要共享一个policy对象 //根据反射原理,同一个方法的MethodInfo是同一个对象,但是对象上取出来的HystrixCommandAttribute //每次获取的都是不同的对象,因此以MethodInfo为Key保存到policies中,确保一个方法对应一个policy实例 policies.TryGetValue(context.ServiceMethod, out AsyncPolicy policy); lock (policies) //因为Invoke可能是并发调用,因此要确保policies赋值的线程安全 { if (policy == null) { policy = Policy.NoOpAsync(); //创建一个空的Policy if (IsEnableCircuitBreaker) { policy = policy.WrapAsync(Policy.Handle <Exception>().CircuitBreakerAsync(IsForceDowngrade ? 1 : ExceptionsAllowedBeforeBreaking, TimeSpan.FromMilliseconds(MillisecondsOfBreak))); } if (TimeOutMilliseconds > 0) { policy = policy.WrapAsync(Policy.TimeoutAsync(() => TimeSpan.FromMilliseconds(TimeOutMilliseconds), TimeoutStrategy.Pessimistic)); } if (MaxRetryTimes > 0) { policy = policy.WrapAsync(Policy.Handle <Exception>().WaitAndRetryAsync(MaxRetryTimes, i => TimeSpan.FromMilliseconds(RetryIntervalMilliseconds))); } AsyncPolicy policyFallBack = Policy .Handle <Exception>() .FallbackAsync(async(ctx, t) => { var fallBackMethod = context.ServiceMethod.DeclaringType.GetMethod(this.FallBackMethod); Object fallBackResult = fallBackMethod.Invoke(context.Implementation, context.Parameters); //不能如下这样,因为这是闭包相关,如果这样写第二次调用Invoke的时候context指向的 //还是第一次的对象,所以要通过Polly的上下文来传递AspectContext //context.ReturnValue = fallBackResult; AspectContext aspectContext = (AspectContext)ctx["aspectContext"]; aspectContext.ReturnValue = fallBackResult; }, async(ex, t) => { t.Add("error", ex.Message); }); policy = policyFallBack.WrapAsync(policy); //放入 policies.TryAdd(context.ServiceMethod, policy); } } //把本地调用的AspectContext传递给Polly,主要给FallbackAsync中使用,避免闭包的坑 Context pollyCtx = new Context(); pollyCtx["aspectContext"] = context; // 强制降级 if (IsForceDowngrade) { await policy.ExecuteAsync((i) => throw new Core.AngleExceptions("force downgrade"), pollyCtx); return; } //Install-Package Microsoft.Extensions.Caching.Memory if (CacheTTLMilliseconds > 0) { //用类名+方法名+参数的下划线连接起来作为缓存key string cacheKey = "HystrixMethodCacheManager_Key_" + context.ServiceMethod.DeclaringType + "." + context.ServiceMethod + string.Join("_", context.Parameters); //尝试去缓存中获取。如果找到了,则直接用缓存中的值做返回值 if (memoryCache.TryGetValue(cacheKey, out var cacheValue)) { context.ReturnValue = cacheValue; } else { //如果缓存中没有,则执行实际被拦截的方法 await policy.ExecuteAsync(ctx => next(context), pollyCtx); //存入缓存中 using (var cacheEntry = memoryCache.CreateEntry(cacheKey)) { cacheEntry.Value = context.ReturnValue; cacheEntry.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMilliseconds(CacheTTLMilliseconds); } } } else //如果没有启用缓存,就直接执行业务方法 { await policy.ExecuteAsync(ctx => next(context), pollyCtx); } }
public override async Task Invoke(AspectContext context, AspectDelegate next) { int methodtoken = context.ServiceMethod.MetadataToken; //System.Reflection.MethodBase.GetCurrentMethod().MetadataToken; this.SetGlobalConfig(); //查询字典中是否保存过当前函数的policy Share.GlobalStatic.dict_policies.TryGetValue(methodtoken, out AsyncPolicy policy); if (policy == null) { policy = this.SetFallBackPolicy(policy, context); AsyncPolicy wrappolicy = null; wrappolicy = this.SetCircuitBreaker(wrappolicy); wrappolicy = this.SetRetry(wrappolicy); wrappolicy = this.SetTimeout(wrappolicy); //如果降级启用,就把降级策略和以上策略进行组合,注意组合顺序,顺序不对可能部分策略失效(不确定) if (IsEnableFallBack == E_Hystrix.Enable) { policy = policy.WrapAsync(wrappolicy); } else { policy = wrappolicy; } //添加的时候,锁住再查询一次看字典中是否存在key,如果存在,说明并发的时候加入过这个,就不需要再加入了 lock (lock_Hystrix) { if (!Share.GlobalStatic.dict_policies.ContainsKey(methodtoken)) { Share.GlobalStatic.dict_policies.TryAdd(methodtoken, policy); } } } //policy.ExecuteAsync执行的时候,把pollyCtx当参数传递过去,避免闭包问题 Context pollyCtx = new Context(); pollyCtx["aspectContext"] = context; //todo:增加缓存算法,不然内存很快爆满,OneNote里有 //全局启用,局部启用,缓存才启用 if (cache != null && cache.Enable && IsEnableCache == E_Hystrix.Enable) { string cacheKey = MD5Helper.MD5Encrypt32("CM_Hystrix_" + context.ServiceMethod.DeclaringType + "." + context.ServiceMethod + string.Join("_", context.Parameters)); //尝试去缓存中获取。如果找到了,则直接用缓存中的值做返回值 if (cache.TryGetValue(cacheKey, out var cacheValue)) { context.ReturnValue = cacheValue; } else { //如果缓存中没有,则执行实际被拦截的方法 await policy.ExecuteAsync(ctx => next(context), pollyCtx); //把返回值存入缓存中 cache.Add(cacheKey, context.ReturnValue, CacheTTLSeconds == 0 ? cache.Expiration : CacheTTLSeconds); } } else//如果没有启用缓存,就直接执行业务方法 { if (policy == null) { await next(context);//直接执行 } else { await policy.ExecuteAsync(ctx => next(context), pollyCtx);//polly执行 } } }
public override Task Invoke(AspectContext context, AspectDelegate next) { var scopedService = context.ServiceProvider.GetService(typeof(ScopedService)); return(context.Invoke(next)); }
public override async Task Invoke(AspectContext context, AspectDelegate next) { //await next(context); //一个HystrixCommand中保持一个policy对象即可 //其实主要是CircuitBreaker要求对于同一段代码要共享一个policy对象 //根据反射原理,同一个方法的MethodInfo是同一个对象,但是对象上取出来的HystrixCommandAttribute //每次获取的都是不同的对象,因此以MethodInfo为Key保存到policies中,确保一个方法对应一个policy实例 //policies.TryGetValue(context.ServiceMethod, out Policy policy); lock (this)//因为Invoke可能是并发调用,因此要确保policies赋值的线程安全 { if (policy == null) { policy = Policy .Handle <ArgumentException>() .FallbackAsync(async(ctx, t) => { AspectContext aspectContext = (AspectContext)ctx["aspectContext"]; var fallBackMethod = context.ServiceMethod.DeclaringType.GetMethod(this.FallBackMethod); Object fallBackResult = fallBackMethod.Invoke(context.Implementation, context.Parameters); //不能如下这样,因为这是闭包相关,如果这样写第二次调用Invoke的时候context指向的 //还是第一次的对象,所以要通过Polly的上下文来传递AspectContext //context.ReturnValue = fallBackResult; aspectContext.ReturnValue = fallBackResult; Console.WriteLine("我也是醉了"); }, async(ex, t) => { //Console.WriteLine("哈哈 我终于进来了"); //context.ReturnValue = "哈哈哈"; Console.WriteLine("我TM也是醉了"); }); // 设置 最大重试次数限制 if (MaxRetryTimes > 0) { policy = policy.WrapAsync(Policy.Handle <ArgumentException>() .WaitAndRetryAsync(MaxRetryTimes, i => TimeSpan.FromMilliseconds(RetryIntervalMilliseconds))); } // 启用熔断保护(CircuitBreaker) if (IsEnableCircuitBreaker) { policy = policy.WrapAsync(Policy.Handle <ArgumentException>() .CircuitBreakerAsync(ExceptionsAllowedBeforeBreaking, TimeSpan.FromMilliseconds(MillisecondsOfBreak), (ex, ts) => { // assuem to do logging Console.WriteLine($"Service API OnBreak -- ts = {ts.Seconds}s, ex.message = {ex.Message}"); }, () => { // assume to do logging Console.WriteLine($"Service API OnReset"); })); } // 设置超时时间 if (TimeOutMilliseconds > 0) { policy = policy.WrapAsync(Policy.TimeoutAsync(() => TimeSpan.FromMilliseconds(TimeOutMilliseconds), Polly.Timeout.TimeoutStrategy.Pessimistic)); } //policy = policyFallBack.WrapAsync(policy); //放入 //policies.TryAdd(context.ServiceMethod, policy); } ; } //把本地调用的AspectContext传递给Polly,主要给FallbackAsync中使用,避免闭包的坑 Context pollyCtx = new Context(); pollyCtx["aspectContext"] = context; //Install-Package Microsoft.Extensions.Caching.Memory if (CacheTTLMilliseconds > 0) { //用类名+方法名+参数的下划线连接起来作为缓存key var cacheKey = CustomCacheKey(context); //尝试去缓存中获取。如果找到了,则直接用缓存中的值做返回值 if (_memoryCache.TryGetValue(cacheKey, out var cacheValue)) { context.ReturnValue = cacheValue; } else { //如果缓存中没有,则执行实际被拦截的方法 await policy.ExecuteAsync(ctx => next(context), pollyCtx); //存入缓存中 using (var cacheEntry = _memoryCache.CreateEntry(cacheKey)) { cacheEntry.Value = context.ReturnValue; cacheEntry.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMilliseconds(CacheTTLMilliseconds); } } } else//如果没有启用缓存,就直接执行业务方法 { await policy.ExecuteAsync(ctx => next(context), pollyCtx); } }
public override Task Invoke(AspectDelegate next) { return(next(this)); }
/// <summary> /// /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <returns></returns> public async override Task Invoke(AspectContext context, AspectDelegate next) { var interceptor = context.ServiceProvider.GetService <AuthorizationInterceptor>(); await interceptor.Invoke(context, next); }
public override void Invoke(AspectContext context, AspectDelegate next) { syncCache.GetOrAdd(context.Method, CreateInvoke)(context, next); }
//public override void OnExit(MethodExecutionArgs args) //{ // var type = (string)args.Arguments[0]; // var code = (string)args.ReturnValue; // Logger.PrintHeader(type); // Logger.PrintLn(code); // base.OnExit(args); //} public override Task Invoke(AspectContext context, AspectDelegate next) { throw new System.NotImplementedException(); }
public override Task Invoke(AspectContext context, AspectDelegate next) { ISyncPolicy policy = Policy .Handle <Exception>() .Fallback(() => { var fallBackMethod = context.ServiceMethod.DeclaringType.GetMethod(this.FallBackMethod); Object fallBackResult = fallBackMethod.Invoke(context.Implementation, context.Parameters); context.ReturnValue = fallBackResult; }); if (MaxRetryTimes > 0) { policy = policy.Wrap(Policy.Handle <Exception>().WaitAndRetry(MaxRetryTimes, i => TimeSpan.FromMilliseconds(RetryIntervalMilliseconds))); } if (EnableCircuitBreaker) { policy = policy.Wrap(Policy.Handle <Exception>().CircuitBreaker(ExceptionsAllowedBeforeBreaking, TimeSpan.FromMilliseconds(RetryIntervalMilliseconds))); } if (TimeOutMilliseconds > 0) { policy = policy.Wrap(Policy.Timeout(() => TimeSpan.FromMilliseconds(TimeOutMilliseconds), TimeoutStrategy.Pessimistic)); } //Install-Package Microsoft.Extensions.Caching.Memory if (CacheTTLMilliseconds > 0) { //用类名+方法名+参数的下划线连接起来作为缓存key string cacheKey = "HystrixMethodCacheManager_Key_" + context.ServiceMethod.DeclaringType + "." + context.ServiceMethod + string.Join("_", context.Parameters); Object cacheValue; //尝试去缓存中获取 if (memoryCache.TryGetValue(cacheKey, out cacheValue)) { context.ReturnValue = cacheValue; return(Task.FromResult(0)); } else { object returnValue = null; policy.Execute(() => { //执行实际的方法 returnValue = context.Invoke(next); }); using (var cacheEntry = memoryCache.CreateEntry(cacheKey)) { cacheEntry.Value = context.ReturnValue; cacheEntry.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMilliseconds(CacheTTLMilliseconds); } return(Task.FromResult(returnValue)); } } else//如果没有启用缓存,就直接执行业务方法 { object returnValue = null; policy.Execute(() => { returnValue = context.Invoke(next); }); return(Task.FromResult(returnValue)); } }
public override async Task Invoke(AspectContext context, AspectDelegate next) { //熔断一般都是针对方法的 //一个HystrixCommand中保持一个policy对象即可 //其实主要是CircuitBreaker要求对于同一段代码要共享一个policy对象 //根据反射原理,同一个方法就对应一个HystrixCommandAttribute,无论几次调用, //而不同方法对应不同的HystrixCommandAttribute对象,天然的一个policy对象共享 //因为同一个方法共享一个policy,因此这个CircuitBreaker是针对所有请求的。 //Attribute也不会在运行时再去改变属性的值,共享同一个policy对象也没问题 lock (this)//因为Invoke可能是并发调用,因此要确保policy赋值的线程安全 { if (policy == null) { policy = Policy.NoOpAsync();//创建一个空的Policy if (EnableCircuitBreaker) { policy = policy.WrapAsync(Policy.Handle <Exception>().CircuitBreakerAsync(ExceptionsAllowedBeforeBreaking, TimeSpan.FromMilliseconds(MillisecondsOfBreak))); } if (TimeOutMilliseconds > 0) { policy = policy.WrapAsync(Policy.TimeoutAsync(() => TimeSpan.FromMilliseconds(TimeOutMilliseconds), Polly.Timeout.TimeoutStrategy.Pessimistic)); } if (MaxRetryTimes > 0) { policy = policy.WrapAsync(Policy.Handle <Exception>().WaitAndRetryAsync(MaxRetryTimes, i => TimeSpan.FromMilliseconds(RetryIntervalMilliseconds))); } Policy policyFallBack = Policy .Handle <Exception>() .FallbackAsync(async(ctx, t) => { AspectContext aspectContext = (AspectContext)ctx["aspectContext"]; var fallBackMethod = context.ServiceMethod.DeclaringType.GetMethod(this.FallBackMethod); Object fallBackResult = fallBackMethod.Invoke(context.Implementation, context.Parameters); //不能如下这样,因为这是闭包相关,如果这样写第二次调用Invoke的时候context指向的 //还是第一次的对象,所以要通过Polly的上下文来传递AspectContext //context.ReturnValue = fallBackResult; aspectContext.ReturnValue = fallBackResult; }, async(ex, t) => { }); policy = policyFallBack.WrapAsync(policy); } } //把本地调用的AspectContext传递给Polly,主要给FallbackAsync中使用,避免闭包的坑 Context pollyCtx = new Context(); pollyCtx["aspectContext"] = context; //Install-Package Microsoft.Extensions.Caching.Memory if (CacheTTLMilliseconds > 0) { //用类名+方法名+参数的下划线连接起来作为缓存key string cacheKey = "HystrixMethodCacheManager_Key_" + context.ServiceMethod.DeclaringType + "." + context.ServiceMethod + string.Join("_", context.Parameters); //尝试去缓存中获取。如果找到了,则直接用缓存中的值做返回值 if (memoryCache.TryGetValue(cacheKey, out var cacheValue)) { context.ReturnValue = cacheValue; } else { //如果缓存中没有,则执行实际被拦截的方法 await policy.ExecuteAsync(ctx => next(context), pollyCtx); //存入缓存中 using (var cacheEntry = memoryCache.CreateEntry(cacheKey)) { cacheEntry.Value = context.ReturnValue; cacheEntry.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMilliseconds(CacheTTLMilliseconds); } } } else//如果没有启用缓存,就直接执行业务方法 { await policy.ExecuteAsync(ctx => next(context), pollyCtx); } }
public override Task Invoke(AspectContext context, AspectDelegate next) { Console.WriteLine("call interceptor"); return(context.Invoke(next)); }
public override async Task Invoke(AspectContext context, AspectDelegate next) { Console.WriteLine("global"); await next(context); }
public async override Task Invoke(AspectContext context, AspectDelegate next) { await next(context); }
public override Task Invoke(AspectContext context, AspectDelegate next) { return(context.Invoke(next)); }
public async override Task Invoke(AspectContext context, AspectDelegate next) { if (!IsOpen) { await next(context); return; } try { var redis = context.ServiceProvider.GetService <IRedisService>(); var option = context.ServiceProvider.GetService <IOptions <CacheOptions> >(); Type returnType = context.GetReturnType(); string key = Utils.GetParamterKey("", "", Key, context.Parameters); var result = redis.HashGet <string>(HashKey, key, option.Value.RedisRead, RedisSerializerOptions.RedisValue); if (result.IsEmpty()) { await next(context); var value = await context.GetReturnValue(); if (value != null) { var json = JsonConvert.SerializeObject(value); if (Seconds > 0) { bool exists = redis.KeyExists(HashKey, option.Value.RedisRead); redis.HashSet(HashKey, key, json, option.Value.RedisWrite, RedisSerializerOptions.RedisValue); if (!exists) { redis.KeyExpire(HashKey, Seconds, option.Value.RedisWrite); } } else { redis.HashSet(HashKey, key, json, option.Value.RedisWrite, RedisSerializerOptions.RedisValue); } } } else { var value = JsonConvert.DeserializeObject(result, returnType); context.ReturnValue = context.ResultFactory(value, returnType, context.IsAsync()); } } catch (Exception ex) { var logger = context.ServiceProvider.GetService <ILogger <RedisCacheMethodAttribute> >(); logger.LogError($"RedisCacheMethod:Key:{Key} {ex.FormatMessage()}"); await next(context); } }
public override Task Invoke(AspectContext context, AspectDelegate next) { context.Parameters[0] = context.Parameters[0].ToString().ToUpper(); return(next(context)); }
public override async Task Invoke(AspectContext context, AspectDelegate next) { InvokeBefore(context); await context.Invoke(next); }
public override async Task Invoke(AspectContext context, AspectDelegate next) { await ProcessGetOrCreateAsync(context, next); }
public override async Task Handle(AspectContext context, AspectDelegate next) { await next(context); }
public abstract Task Invoke(AspectContext context, AspectDelegate next);
/// <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); } } }
/// <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 => 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 = null; var isAvailable = true; try { cacheValue = await _cacheProvider.GetAsync(cacheKey, returnType); } catch (Exception ex) { if (!attribute.IsHightAvailability) { throw; } else { isAvailable = false; Logger?.LogError(new EventId(), ex, $"Cache provider \"{_cacheProvider.Name}\" 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) { 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); } }