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;
|
}
|
}
|
}
|