【问题标题】:Autofac implements AOP cache error reporting for task methodAutofac为task方法实现AOP缓存报错
【发布时间】:2021-08-18 10:15:32
【问题描述】:

我为一个任务方法实现了 AOP。在AOP中,我实现了缓存的逻辑。在方法执行之前,我进入AOP的逻辑判断是否有缓存。如果缓存命中,我直接返回。如果缓存没有命中,我执行方法,然后将方法的执行结果插入缓存。但是,如果命中缓存,则报如下错误

  InnerException    
{"Unable to cast object of type 'System.Threading.Tasks.Task`1[System.Object]' to type 
'System.Threading.Tasks.Task`1[System.Collections.Generic.List`1[cooperation_error_typeModel]]'."}  
System.Exception {System.InvalidCastException}

    /// <summary>
    /// 
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, Inherited = false)]
    public class CacheAttribute: Attribute
    {
        /// <summary>
        /// 
        /// </summary>
        public int ExpirationSeconds { get; }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="expirationSeconds"></param>
        public CacheAttribute(int expirationSeconds)
        { 
            this.ExpirationSeconds = expirationSeconds;
        }
    }


    [Intercept(typeof(CacheInterceptor))]
    [Repository]
    public class CoopErrorTypeRepository : ICoopErrorTypeRepository
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="coopId"></param>
        /// <returns></returns>
        [Cache(300)]
        public async Task<IEnumerable<cooperation_error_typeModel>> GetCoopErrorTypeList(string coopId)
        {
          return new cooperation_error_typeModel();
        }
    }

       public class CacheInterceptor : IInterceptor
    {
        /// <summary>
        /// Intercept
        /// </summary>
        /// <param name="invocation"></param>
        public void Intercept(IInvocation invocation)
        {
            var method = invocation.MethodInvocationTarget ?? invocation.Method;
            var cacheAttribute = this.GetQCachingAttributeInfo(method);
            if (cacheAttribute != null)
            {
                ProceedCaching(invocation, cacheAttribute, method);
            }
            else
            {
                invocation.Proceed();
            }
        }

        private CacheAttribute GetQCachingAttributeInfo(MethodInfo method)
        {
            return method.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(CacheAttribute)) as CacheAttribute;
        }

        private void ProceedCaching(IInvocation invocation, CacheAttribute attribute, MethodInfo method)
        { 
            var cacheKey = GetCacheKey(invocation.Arguments); 
            var client = RedisHelper.redisClientFactory.GetClient("CooperationDataCache"); 
            var cacheValue = client.String.Get(cacheKey); 
            if (!string.IsNullOrWhiteSpace(cacheValue))
            {
                if (method.ReturnType.BaseType == (typeof(Task)))
                {
                    Type[] genericTypeArguments = method.ReturnType.GenericTypeArguments;
                    if (genericTypeArguments != null && genericTypeArguments.Length > 0)
                    {
                        invocation.ReturnValue = Task.FromResult(JsonConvert.DeserializeObject(cacheValue, genericTypeArguments[0]));
                    }
                }
            }
            else
            {
                invocation.Proceed();

                if (method.ReturnType.BaseType == (typeof(Task)))
                {

                    //if (!(method.Invoke(invocation.InvocationTarget, invocation.Arguments) is Task task)) return;
                    var task = (Task)invocation.ReturnValue;
                    task.ContinueWith(m =>
                                {
                                    if (task.Status != TaskStatus.RanToCompletion) return;
                                    var result = ConvertHelperExtend.PackJson(((dynamic)task).Result);
                                    client.String.Set(cacheKey, result);
                                    client.Key.Expire(cacheKey, attribute.ExpirationSeconds);
                                });
                }
                else
                {
                    client.String.Set(cacheKey, ConvertHelperExtend.PackJson(invocation.ReturnValue));
                    client.Key.Expire(cacheKey, attribute.ExpirationSeconds);
                }
            }
        }

        /// <summary>
        /// get cache key
        /// </summary>
        /// <param name="invocation"></param>
        /// <returns></returns>
        private string GetCacheKey(object[] arguments)
        {
            if (arguments == null || arguments.Length < 1) return string.Empty;

            foreach (var argument in arguments)
            {
                if (argument is IGetCacheKey cacheKeyObj)
                    return cacheKeyObj.CacheKey;
            }
            return string.Empty;
        }
    }


    /// <summary>
    /// cache key
    /// </summary>
    public interface IGetCacheKey
    {
        /// <summary>
        /// cache key
        /// </summary>
        string CacheKey { get; }
    }

【问题讨论】:

  • 您可能无法在此处获得答案。您发布的异常并没有告诉任何人它在代码中发生的位置,也没有人会设置一个完整的重现解决方案来为您调试它。自己调试更多并描述您发现的内容可能会更好。

标签: c# autofac aop castle


【解决方案1】:

我解决了这个问题,但不是很理想。

invocation.ReturnValue = Task.FromResult(JsonConvert.DeserializeObject(cacheValue, genericTypeArguments[0]));

替换:

invocation.ReturnValue = Task.FromResult((dynamic) JsonConvert.DeserializeObject(cacheValue, genericTypeArguments[0]));

它对我有用。

想要: 缓存方法返回类型不能是泛型的接口和接口。

希望有人能解决

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-17
    • 1970-01-01
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-20
    相关资源
    最近更新 更多