//
namespace SafeCampus.Plugin.Aop;
///
/// Aop
/// 这里没有继承IGlobalDispatchProxy是因为IGlobalDispatchProxy会把一些没有必要的方法也aop了
///
public class GlobalDispatchProxy : AspectDispatchProxy, IDispatchProxy
{
///
/// 当前服务实例
///
public object Target { get; set; }
///
/// 服务提供器,可以用来解析服务,如:Services.GetService()
///
public IServiceProvider Services { get; set; }
///
/// 方法
///
///
///
///
///
public override object Invoke(MethodInfo method, object[] args)
{
//如果不带返回值
if (method.ReturnType == typeof(void))
{
After(method, null, args);
return method.Invoke(Target, args);//直接返回
}
var result = Before(method, args);//方法执行之前判断是否有缓存的数据
if (result == null) result = method.Invoke(Target, args);//如果没有缓存就执行方法返回数据
After(method, result, args);//方法执行之后干的事
return result;//返回结果
}
///
/// 异步无返回值
///
///
///
///
///
public override async Task InvokeAsync(MethodInfo method, object[] args)
{
var task = method.Invoke(Target, args) as Task;
await task;
After(method, null, args);
}
///
/// 异步带返回值
///
///
///
///
///
///
public override async Task InvokeAsyncT(MethodInfo method, object[] args)
{
var result = Before(method, args);//方法执行之前判断是否有缓存的数据
if (result == null)
{
var taskT = method.Invoke(Target, args) as Task;
result = await taskT;//如果没有缓存就执行方法返回数据
}
After(method, result, args);//方法执行之后干的事
return result;//返回结果
}
///
/// 方法执行之后
///
/// 方法
/// 返回值
/// 参数列表
private void After(MethodInfo method, object returnValue, object[] args)
{
RecordCache(method, args, returnValue);//记录返回值到缓存
}
///
/// 方法执行之前
///
/// 方法
/// 参数列表
///
private dynamic Before(MethodInfo method, object[] args)
{
var cacheData = CheckCache(method, args);//检查缓存
if (cacheData != null) { return cacheData; }//如果缓存有数据直接返回
return null;//默认返回空
}
///
/// 检查缓存里是否有数据
///
/// 方法
/// 参数列表
private dynamic CheckCache(MethodInfo method, object[] args)
{
var cacheAttribute = method.GetActualCustomAttribute(Target);//读取缓存特性
//判断需不需要读取缓存
if (cacheAttribute != null)
{
var redisManager = Services.GetService();// 获取redis服务
var cacheKey = cacheAttribute.CustomKeyValue
?? CustomCacheKey(cacheAttribute.KeyPrefix, method, args);//如果redisKey值,如果有自定义值就用自定义Key,否则以前缀+系统自动生成的Key
string cacheValue;
if (cacheAttribute.StoreType == CacheConst.CACHE_HASH)//如果存的是Hash值
{
cacheValue = redisManager.HashGet(cacheKey, args[0].ToString())[0];//从redis获取Hash数据取第一个,注意是 string 类型
}
else
{
cacheValue = redisManager.Get(cacheKey);//注意是 string 类型,方法GetValue
}
if (!string.IsNullOrEmpty(cacheValue))//如果返回值不是空
{
//if (cacheAttribute.IsDelete)//判断是否是删除操作
//{
// if (cacheAttribute.StoreType == RedisConst.Cache_Hash)//如果是Hash
// {
// _redisManager.HashDel(cacheKey, new string[] { args[0].ToString() });
// }
// else
// {
// //删除Redis整个KEY
// _redisManager.Remove(cacheKey);
// }
//}
//将当前获取到的缓存值,赋值给当前执行方法
Type returnType;
if (typeof(Task).IsAssignableFrom(method.ReturnType))
{
returnType = method.ReturnType.GenericTypeArguments.FirstOrDefault();
}
else
{
returnType = method.ReturnType;
}
if (!returnType.IsPrimitive && returnType != typeof(string))//判断返回类型是否原生类型并且不是string
{
dynamic result = JsonConvert.DeserializeObject(cacheValue, returnType);//序列化数据
return result;
}
return cacheValue;
}
}
return null;
}
///
/// 写数据到缓存
///
/// 方法
/// 参数列表
/// 返回值
private void RecordCache(MethodInfo method, object[] args, object returnValue)
{
var cacheAttribute = method.GetActualCustomAttribute(Target);
if (cacheAttribute != null)
{
//获取自定义缓存键
var cacheKey = cacheAttribute.CustomKeyValue ?? CustomCacheKey(cacheAttribute.KeyPrefix, method, args);
if (!string.IsNullOrWhiteSpace(cacheKey))//如果有key
{
var redisManager = Services.GetService();// 获取redis服务
if (cacheAttribute.IsDelete)//判断是否是删除操作
{
//删除Redis整个KEY
redisManager.Remove(cacheKey);
}
else
{
if (returnValue == null) { return; }
if (cacheAttribute.StoreType == CacheConst.CACHE_HASH)//如果是hash类型的
{
//插入到hash,这里规定是方法的第一个参数
redisManager.HashAdd(cacheKey, args[0].ToString(), returnValue);
}
else
{
if (cacheAttribute.AbsoluteExpiration != null)//如果有超时时间
{
redisManager.Set(cacheKey, returnValue, cacheAttribute.AbsoluteExpiration.Value);//插入redis
}
else
{
redisManager.Set(cacheKey, returnValue);//插入redis
}
}
}
}
}
}
///
/// 自定义缓存Key
///
/// 前缀
/// 方法
/// 参数
///
protected string CustomCacheKey(string prefix, MethodInfo method, object[] args)
{
var key = prefix;//前缀
var methodArguments = args.Select(GetCacheKey.GetArgumentValue).Take(3).ToList();//获取参数列表,最多三个
if (!string.IsNullOrEmpty(key))//如果制定了前缀
{
foreach (var param in methodArguments)//遍历参数列表
{
key = $"{key}{param}:";//生成KEY
}
}
else
{
var typeName = Target.GetType().Name;//获取实例名
var methodName = method.Name;//获取方法名
key = $"{CacheConst.CACHE_PREFIX_WEB}{typeName}:{methodName}:";//生成Key
foreach (var param in methodArguments)//遍历参数列表
{
key = $"{key}{param}:";//生成加上参数的KEY
}
}
return key.TrimEnd(':');
}
}
///
/// 获取缓存Key
///
internal static class GetCacheKey
{
///
/// object 转 string
///
///
///
public static string GetArgumentValue(object arg)
{
if (arg is DateTime || arg is DateTime)
return ((DateTime)arg).ToString("yyyyMMddHHmmss");
if (arg is string || arg is ValueType || arg is Nullable)
return arg.ToString();
if (arg != null)
{
if (arg is Expression)
{
var obj = arg as Expression;
var result = Resolve(obj);
return MD5Encryption.Encrypt(result);
}
if (arg.GetType().IsClass)
{
return MD5Encryption.Encrypt(JsonConvert.SerializeObject(arg));
}
}
return string.Empty;
}
private static string Resolve(Expression expression)
{
if (expression is LambdaExpression)
{
var lambda = expression as LambdaExpression;
expression = lambda.Body;
return Resolve(expression);
}
if (expression is BinaryExpression)
{
var binary = expression as BinaryExpression;
if (binary.Left is MemberExpression && binary.Right is ConstantExpression)//解析x=>x.Name=="123" x.Age==123这类
return ResolveFunc(binary.Left, binary.Right, binary.NodeType);
if (binary.Left is MethodCallExpression && binary.Right is ConstantExpression)//解析x=>x.Name.Contains("xxx")==false这类的
{
var value = (binary.Right as ConstantExpression).Value;
return ResolveLinqToObject(binary.Left, value, binary.NodeType);
}
if (binary.Left is MemberExpression && binary.Right is MemberExpression
|| binary.Left is MemberExpression && binary.Right is UnaryExpression)//解析x=>x.Date==DateTime.Now这种
{
var lambda = Expression.Lambda(binary.Right);
var fn = lambda.Compile();
var value = Expression.Constant(fn.DynamicInvoke(null), binary.Right.Type);
return ResolveFunc(binary.Left, value, binary.NodeType);
}
}
if (expression is UnaryExpression)
{
var unary = expression as UnaryExpression;
if (unary.Operand is MethodCallExpression)//解析!x=>x.Name.Contains("xxx")或!array.Contains(x.Name)这类
return ResolveLinqToObject(unary.Operand, false);
if (unary.Operand is MemberExpression && unary.NodeType == ExpressionType.Not)//解析x=>!x.isDeletion这样的
{
var constant = Expression.Constant(false);
return ResolveFunc(unary.Operand, constant, ExpressionType.Equal);
}
}
if (expression is MemberExpression && expression.NodeType == ExpressionType.MemberAccess)//解析x=>x.isDeletion这样的
{
var member = expression as MemberExpression;
var constant = Expression.Constant(true);
return ResolveFunc(member, constant, ExpressionType.Equal);
}
if (expression is MethodCallExpression)//x=>x.Name.Contains("xxx")或array.Contains(x.Name)这类
{
var methodcall = expression as MethodCallExpression;
return ResolveLinqToObject(methodcall, true);
}
//已经修改过代码body应该不会是null值了
if (!(expression is BinaryExpression body))
return string.Empty;
var @operator = GetOperator(body.NodeType);
var left = Resolve(body.Left);
var right = Resolve(body.Right);
var result = string.Format("({0} {1} {2})", left, @operator, right);
return result;
}
private static string ResolveFunc(Expression left, Expression right, ExpressionType expressiontype)
{
var name = (left as MemberExpression).Member.Name;
var value = (right as ConstantExpression).Value;
var @operator = GetOperator(expressiontype);
return name + @operator + value;
}
private static string ResolveLinqToObject(Expression expression, object value, ExpressionType? expressiontype = null)
{
var methodCall = expression as MethodCallExpression;
var methodName = methodCall.Method.Name;
switch (methodName)
{
case "Contains":
return methodCall.Object != null ? Like(methodCall) : In(methodCall, value);
case "Count":
return Len(methodCall, value, expressiontype.Value);
case "LongCount":
return Len(methodCall, value, expressiontype.Value);
default:
throw new Exception(string.Format("不支持{0}方法的查找!", methodName));
}
}
private static string GetOperator(ExpressionType expressiontype)
{
return expressiontype switch
{
ExpressionType.And => "and",
ExpressionType.AndAlso => "and",
ExpressionType.Or => "or",
ExpressionType.OrElse => "or",
ExpressionType.Equal => "=",
ExpressionType.NotEqual => "<>",
ExpressionType.LessThan => "<",
ExpressionType.LessThanOrEqual => "<=",
ExpressionType.GreaterThan => ">",
ExpressionType.GreaterThanOrEqual => ">=",
_ => throw new Exception(string.Format("不支持{0}此种运算符查找!" + expressiontype))
};
}
private static string In(MethodCallExpression expression, object isTrue)
{
var argument1 = (expression.Arguments[0] as MemberExpression).Expression as ConstantExpression;
var argument2 = expression.Arguments[1] as MemberExpression;
var fieldArray = argument1.Value.GetType().GetFields().First();
var array = fieldArray.GetValue(argument1.Value) as object[];
var setInPara = new List();
for (var i = 0; i < array.Length; i++)
{
var value = array[i].ToString();
setInPara.Add(value);
}
var name = argument2.Member.Name;
var @operator = Convert.ToBoolean(isTrue) ? "in" : " not in";
var compName = string.Join(",", setInPara);
var result = string.Format("{0} {1} ({2})", name, @operator, compName);
return result;
}
private static string Like(MethodCallExpression expression)
{
var temp = expression.Arguments[0];
var lambda = Expression.Lambda(temp);
var fn = lambda.Compile();
var tempValue = Expression.Constant(fn.DynamicInvoke(null), temp.Type);
var value = string.Format("%{0}%", tempValue);
var name = (expression.Object as MemberExpression).Member.Name;
var result = string.Format("{0} like {1}", name, value);
return result;
}
private static string Len(MethodCallExpression expression, object value, ExpressionType expressiontype)
{
object name = (expression.Arguments[0] as MemberExpression).Member.Name;
var @operator = GetOperator(expressiontype);
var result = string.Format("len({0}){1}{2}", name, @operator, value);
return result;
}
}