wankeda
2025-04-15 9bae33c85d698987a6c9cf8ba8edbe9497b101dc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
using Castle.DynamicProxy;
using Newtonsoft.Json;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Attributes;
using WIDESEAWCS_Core.Caches;
using WIDESEAWCS_Core.Helper;
using ICacheService = WIDESEAWCS_Core.Caches.ICacheService;
 
namespace WIDESEAWCS_Core.AOP
{
    public class CacheAOP : IInterceptor
    {
        private readonly ICacheService _cacheService;
        public CacheAOP(ICacheService cacheService)
        {
            _cacheService = cacheService;
        }
 
        public void Intercept(IInvocation invocation)
        {
            var method = invocation.MethodInvocationTarget ?? invocation.Method;
 
            var cacheAttribute = method.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(CacheAttribute));
            if (cacheAttribute is CacheAttribute qCachingAttribute)
            {
                //获取自定义缓存键
                var cacheKey = CustomCacheKey(invocation);
                if (_cacheService.Exists(cacheKey))
                {
                    //将当前获取到的缓存值,赋值给当前执行方法
                    Type returnType;
                    if (typeof(Task).IsAssignableFrom(method.ReturnType))
                    {
                        returnType = method.ReturnType.GenericTypeArguments.FirstOrDefault();
                    }
                    else
                    {
                        returnType = method.ReturnType;
                    }
 
                    //根据key获取相应的缓存值
                    dynamic? cacheValue = _cacheService.Get(returnType, cacheKey);
                    if (cacheValue != null)
                        invocation.ReturnValue = (typeof(Task).IsAssignableFrom(method.ReturnType)) ? Task.FromResult(cacheValue) : cacheValue;
                    return;
                }
 
                //去执行当前的方法
                invocation.Proceed();
                //存入缓存
                if (!string.IsNullOrWhiteSpace(cacheKey))
                {
                    object response;
 
                    //Type type = invocation.ReturnValue?.GetType();
                    var type = invocation.Method.ReturnType;
                    if (typeof(Task).IsAssignableFrom(type))
                    {
                        dynamic result = invocation.ReturnValue;
                        response = result.Result;
                    }
                    else
                    {
                        response = invocation.ReturnValue;
                    }
 
                    if (response == null) response = string.Empty;
 
                    _cacheService.AddOrUpdate(cacheKey, response.Serialize(), qCachingAttribute.AbsoluteExpiration * 60);
                }
            }
            else
            {
                invocation.Proceed(); //直接执行被拦截方法
            }
        }
 
        /// <summary>
        /// 自定义缓存的key
        /// </summary>
        /// <param name="invocation"></param>
        /// <returns></returns>
        protected string CustomCacheKey(IInvocation invocation)
        {
            var typeName = invocation.TargetType.Name;
            //获取调用目标类型名称
            var methodName = invocation.Method.Name;
            //获取调用方法名称
            var methodArguments = invocation.Arguments.Select(GetArgumentValue).Take(3).ToList();//获取参数列表,最多三个
 
            string key = $"{typeName}:{methodName}:";
            //定义key,格式为:类型名称:方法名称:
            foreach (var param in methodArguments)
            {
                key = $"{key}{param}:";
                //遍历参数列表,将参数值添加到key中,格式为:参数值:
            }
 
            return key.TrimEnd(':');
            //返回key,去掉末尾的冒号
        }
 
        /// <summary>
        /// object 转 string
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        protected static string GetArgumentValue(object arg)
        {
            if (arg is DateTime)
                // 如果arg是DateTime类型,则返回其字符串表示形式
                return ((DateTime)arg).ToString("yyyyMMddHHmmss");
 
            if (!arg.IsNotEmptyOrNull())
                // 如果arg不是空或null,则返回其字符串表示形式
                return arg.ObjToString();
 
            if (arg != null)
            {
                // 如果arg不是空或null
                if (arg is Expression)
                {
                    // 如果arg是Expression类型
                    var obj = arg as Expression;
                    // 解析arg
                    var result = Resolve(obj);
                    // 返回MD5加密后的字符串
                    return MD5Helper.MD5Encrypt16(result);
                }
                else if (arg.GetType().IsClass)
                {
                    // 如果arg是类类型
                    // 将arg序列化为JSON字符串
                    return MD5Helper.MD5Encrypt16(JsonConvert.SerializeObject(arg));
                }
 
                // 否则,返回"value:"加上arg的字符串表示形式
                return $"value:{arg.ObjToString()}";
            }
            // 如果arg是空或null,则返回空字符串
            return string.Empty;
        }
 
        private static string Resolve(Expression expression)
        {
            // 创建一个ExpressionContext对象
            ExpressionContext expContext = new ExpressionContext();
            // 解析表达式,并指定解析类型为WhereSingle
            expContext.Resolve(expression, ResolveExpressType.WhereSingle);
            // 获取解析结果
            var value = expContext.Result.GetString();
            // 获取参数列表
            var pars = expContext.Parameters;
 
            // 遍历参数列表
            pars.ForEach(s =>
            {
                // 将参数名替换为参数值
                value = value.Replace(s.ParameterName, s.Value.ObjToString());
            });
 
            // 返回替换后的值
            return value;
        }
    }
}