@@ -23,7 +23,7 @@ namespace HealthMonitor.Core.Aop | |||
var pipeline = new AopCachePipeline(); | |||
pipeline.AddValue(new AssertValidQueryValue()); | |||
//pipeline.AddValue(new TryGetRefManagerValue()); | |||
pipeline.AddValue(new TryGetRefManagerValue()); | |||
pipeline.AddValue(new GetOrInsertEntityCacheValue()); | |||
pipeline.AddValue(new AopEndPipeValue()); | |||
await pipeline.Start(pipeContext); | |||
@@ -1,7 +0,0 @@ | |||
namespace HealthMonitor.Core | |||
{ | |||
public class Class1 | |||
{ | |||
} | |||
} |
@@ -1,4 +1,7 @@ | |||
namespace HealthMonitor.Core.Operator | |||
using HealthMonitor.Core.Common; | |||
using HealthMonitor.Util.Common.Operator; | |||
namespace HealthMonitor.Core.Operator | |||
{ | |||
/// <summary> | |||
/// HealthMonitor数据库的批量操作缓存管理器 | |||
@@ -1,30 +0,0 @@ | |||
using AspectCore.DynamicProxy; | |||
using HealthMonitor.Core.Common; | |||
namespace HealthMonitor.Core.Pipeline.Aop.Delete | |||
{ | |||
public class AssertValidDeleteHisValue : AopValueBase | |||
{ | |||
public override async Task Invoke(CacheInterceptorContext context) | |||
{ | |||
//方法需要存在参数用于生成缓存键和获取实体类型 | |||
if (context.AopContext.Parameters.Length < 2 || context.AopContext.Parameters[0] == null) | |||
{ | |||
throw new AssertValidException(); | |||
} | |||
var param = context.AopContext.Parameters[0]; | |||
var entityType = param.GetType(); | |||
context.IsAsyncMethod = context.AopContext.IsAsync(); | |||
context.EntityType = entityType; | |||
context.RequestId = context.AopContext.Parameters.Length > 2 ? context.AopContext.Parameters[2] + "" : ""; | |||
using (var scope = context.Logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = context.RequestId })) | |||
using (new CustomizeStopWatch($"删除历史aop[{entityType.Name}]", context.Logger)) | |||
{ | |||
await InvokeNextAsync(context); | |||
} | |||
} | |||
} | |||
} |
@@ -1,46 +0,0 @@ | |||
using Microsoft.Extensions.DependencyInjection; | |||
using HealthMonitor.Core.Cache; | |||
using HealthMonitor.Util.Common; | |||
using HealthMonitor.Util.Entities.Interfaces; | |||
namespace HealthMonitor.Core.Pipeline.Aop.Delete | |||
{ | |||
public class DeleteEntityCacheHisValue : AopValueBase | |||
{ | |||
public override async Task Invoke(CacheInterceptorContext context) | |||
{ | |||
var entityType = context.EntityType; | |||
var param = context.AopContext.Parameters[0]; | |||
var paramImei = context.AopContext.Parameters[1] as string; | |||
var paramDate = (context.AopContext.Parameters.Length > 2 ? context.AopContext.Parameters[2] : null) as DateTime?; | |||
//自增型主键无法预测其键值,所以不做缓存 | |||
if (EntityUtils.HasAutoGenerateKey(entityType)) | |||
{ | |||
await InvokeNextAsync(context); | |||
return; | |||
} | |||
var durableManager = context.AopContext.ServiceProvider.GetService<IDurableEntityManager>(); | |||
var cacheHandler = durableManager?.GetCacheHandler(entityType); | |||
//若实体类型不支持缓存,则退出 | |||
if (cacheHandler == null || cacheHandler.DurableSecond <= 0) | |||
{ | |||
await InvokeNextAsync(context); | |||
return; | |||
} | |||
string id = entityType!.GetMethod(nameof(IEntity.GetPrimaryKey))?.Invoke(param, null) + ""; | |||
if (!string.IsNullOrEmpty(id)) | |||
{ | |||
string key = durableManager!.CalcHistoryCacheKey(entityType, id, paramImei!, paramDate); | |||
if (!string.IsNullOrEmpty(key)) | |||
{ | |||
cacheHandler.DeleteEntityCache(key); | |||
} | |||
} | |||
await InvokeNextAsync(context); | |||
} | |||
} | |||
} |
@@ -1,54 +0,0 @@ | |||
using AspectCore.DynamicProxy; | |||
using AspectCore.DynamicProxy.Parameters; | |||
using System.Collections; | |||
using HealthMonitor.Core.Common; | |||
namespace HealthMonitor.Core.Pipeline.Aop.Query | |||
{ | |||
public class AssertValidQueryHisValue : AopValueBase | |||
{ | |||
public override async Task Invoke(CacheInterceptorContext context) | |||
{ | |||
var methodReturnType = context.AopContext.GetReturnParameter().Type; | |||
//先判断方法是否有返回值,无就不进行缓存判断 | |||
if (methodReturnType == typeof(void) || methodReturnType == typeof(Task)) | |||
{ | |||
throw new AssertValidException(); | |||
} | |||
//方法需要存在参数用于生成缓存键 | |||
if (context.AopContext.Parameters.Length < 3) | |||
{ | |||
throw new AssertValidException(); | |||
} | |||
var returnType = methodReturnType; | |||
//判断是否是异步方法 | |||
bool isAsync = context.AopContext.IsAsync(); | |||
if (isAsync) | |||
{ | |||
//取得异步返回的类型 | |||
returnType = methodReturnType.GenericTypeArguments.FirstOrDefault(); | |||
} | |||
var entityType = returnType; | |||
bool isEnumerable = false; | |||
if (returnType?.GetInterface(typeof(IEnumerable).Name) != null) | |||
{ | |||
entityType = returnType.GenericTypeArguments.FirstOrDefault(); | |||
isEnumerable = true; | |||
} | |||
context.EntityType = entityType!; | |||
context.ReturnType = returnType!; | |||
context.IsAsyncMethod = isAsync; | |||
context.IsReturnEnumerable = isEnumerable; | |||
context.RequestId = context.AopContext.Parameters.Length > 3 ? context.AopContext.Parameters[3] + "" : ""; | |||
using (var scope = context.Logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = context.RequestId })) | |||
using (new CustomizeStopWatch($"查询历史aop[{entityType?.Name}]", context.Logger)) | |||
{ | |||
await InvokeNextAsync(context); | |||
} | |||
} | |||
} | |||
} |
@@ -1,77 +0,0 @@ | |||
using AspectCore.DynamicProxy; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.Logging; | |||
using System.Reflection; | |||
using HealthMonitor.Core.Cache; | |||
using HealthMonitor.Util.Models; | |||
namespace HealthMonitor.Core.Pipeline.Aop.Query | |||
{ | |||
public class GetOrInsertEntityCacheHisValue : AopValueBase | |||
{ | |||
private static MethodInfo M_TaskFromResult = typeof(Task).GetMethod(nameof(Task.FromResult))!; | |||
public override async Task Invoke(CacheInterceptorContext context) | |||
{ | |||
var entityType = context.EntityType; | |||
var returnType = context.ReturnType; | |||
var isAsync = context.IsAsyncMethod; | |||
var isEnumerable = context.IsReturnEnumerable; | |||
var param = context.AopContext.Parameters[0]; | |||
var paramImei = context.AopContext.Parameters[1] as string; | |||
var paramDate = context.AopContext.Parameters[2] as DateTime?; | |||
string? key = null; | |||
//读取缓存 | |||
var durableManager = context.AopContext.ServiceProvider.GetService<IDurableEntityManager>(); | |||
var cacheHandler = durableManager?.GetCacheHandler(entityType); | |||
//若实体类型不支持缓存,则退出 | |||
if (cacheHandler == null || cacheHandler.DurableSecond <= 0) | |||
{ | |||
await InvokeNextAsync(context); | |||
return; | |||
} | |||
if (param is string) key = durableManager?.CalcHistoryCacheKey(entityType, param.ToString()!, paramImei!, paramDate); | |||
else if (param is GeneralParam) key = durableManager?.CalcHistoryCacheKey(entityType, (param as GeneralParam)!, paramImei!, paramDate); | |||
if (string.IsNullOrEmpty(key)) | |||
{ | |||
await InvokeNextAsync(context); | |||
return; | |||
} | |||
var cache = cacheHandler.GetEntitiesCache(key); | |||
object? returnValue; | |||
if (cache != null) | |||
{ | |||
context.Logger.LogInformation($"击中实体缓存{key}"); | |||
returnValue = isEnumerable ? cache : cache.FirstOrDefault(); | |||
if (isAsync) //&& methodReturnType == typeof(Task<>).MakeGenericType(returnType)) | |||
{ | |||
//反射获取Task<>类型的返回值,相当于Task.FromResult(value); | |||
context.AopContext.ReturnValue = M_TaskFromResult.MakeGenericMethod(returnType).Invoke(null, new[] { returnValue }); | |||
return; | |||
} | |||
context.AopContext.ReturnValue = returnValue; | |||
return; | |||
} | |||
await InvokeNextAsync(context); | |||
if (isAsync) | |||
{ | |||
returnValue = await context.AopContext.UnwrapAsyncReturnValue(); | |||
//反射获取异步结果的值,相当于(context.ReturnValue as Task<>).Result | |||
//returnValue = typeof(Task<>).MakeGenericType(returnType).GetProperty(nameof(Task<object>.Result)).GetValue(context.ReturnValue); | |||
} | |||
else | |||
{ | |||
returnValue = context.AopContext.ReturnValue; | |||
} | |||
cacheHandler.SetEntityCache(key, returnValue, isEnumerable); | |||
} | |||
} | |||
} |
@@ -0,0 +1,100 @@ | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.Logging; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Reflection; | |||
using System.Threading.Tasks; | |||
using HealthMonitor.Core.Operator; | |||
using HealthMonitor.Util.Common.Operator; | |||
using HealthMonitor.Util.Entities.Base; | |||
using HealthMonitor.Util.Entities.Interfaces; | |||
namespace HealthMonitor.Core.Pipeline.Aop.Query | |||
{ | |||
public class TryGetRefManagerValue:AopValueBase | |||
{ | |||
private readonly static MethodInfo M_TaskFromResult = typeof(Task).GetMethod(nameof(Task.FromResult))!; | |||
public override async Task Invoke(CacheInterceptorContext context) | |||
{ | |||
var entityType = context.EntityType; | |||
var returnType = context.ReturnType; | |||
var isAsync = context.IsAsyncMethod; | |||
var isEnumerable = context.IsReturnEnumerable; | |||
var param = context.AopContext.Parameters[0]; | |||
if (entityType == null || returnType == null | |||
|| isEnumerable //从待插入队列中读取实体,不支持读取多个实体(列表) | |||
|| !(param is string)) | |||
{ | |||
await InvokeNextAsync(context); | |||
return; | |||
} | |||
//计算key值 | |||
var entity = Activator.CreateInstance(entityType); | |||
var method = entityType.GetMethod(nameof(IEntity.GetUniqueKey)); | |||
var key = method?.Invoke(entity, new[] { param }) + ""; | |||
if (string.IsNullOrEmpty(key)) | |||
{ | |||
await InvokeNextAsync(context); | |||
return; | |||
} | |||
OperateCacheItem cacheItem = null!; | |||
bool isDeleted = false; | |||
/* | |||
* 注意这里是有并发的可能性(负责增删改的后台线程会执行2个步骤:a、从待插入列表中获取并删除实体数据,b、获取到的实体数据入库,当查询发生在a与b之间就会出现该并发情况) | |||
* 因为该并发情况发生几率很低,而且更重要的一点是查询的性能要求比较高尽量不能加互斥锁,所以该并发允许存在,不作修改 | |||
*/ | |||
IOperatorManager operatorManager = null!; | |||
//if (entityType.IsSubclassOf(typeof(GpsCardEntityBase))) operatorManager = context.AopContext.ServiceProvider.GetService<IGpsCardOperatorManager>(); | |||
//else if (entityType.IsSubclassOf(typeof(TelpoCommonEntityBase))) operatorManager = context.AopContext.ServiceProvider.GetService<ITelpoCommonOperatorManager>(); | |||
if (operatorManager != null) | |||
{ | |||
cacheItem = operatorManager.GetDelayOperator(DelayOperateTypeEnum.Insert, key)!; | |||
if (cacheItem == null) cacheItem = operatorManager.GetDelayOperator(DelayOperateTypeEnum.Update, key)!; | |||
if (cacheItem == null && operatorManager.GetDelayOperator(DelayOperateTypeEnum.Delete, key) != null) isDeleted = true; | |||
//从pending状态的数据中检索 | |||
if (cacheItem == null && operatorManager.PendingInsertOperators != null) operatorManager.PendingInsertOperators.TryGetValue(key, out cacheItem!); | |||
if (cacheItem == null && operatorManager.PendingUpdateOperators != null) operatorManager.PendingUpdateOperators.TryGetValue(key, out cacheItem!); | |||
if (cacheItem != null) | |||
{ | |||
context.Logger.LogInformation($"击中操作缓存{key}"); | |||
entity = JsonConvert.DeserializeObject(cacheItem.JsonData!, entityType) as IEntity; //强制转换as将导致返回null或者IEntity实例,然后赋值给object类型 | |||
if (entity != null) | |||
{ | |||
if (isAsync) //&& methodReturnType == typeof(Task<>).MakeGenericType(returnType)) | |||
{ | |||
//反射获取Task<>类型的返回值,相当于Task.FromResult(value); | |||
context.AopContext.ReturnValue = M_TaskFromResult.MakeGenericMethod(returnType).Invoke(null, new[] { entity }); | |||
return; | |||
} | |||
context.AopContext.ReturnValue = entity; | |||
return; | |||
} | |||
} | |||
} | |||
if (isDeleted) | |||
{ | |||
if (isAsync) | |||
{ | |||
//反射获取Task<>类型的返回值,相当于Task.FromResult(value); | |||
context.AopContext.ReturnValue = M_TaskFromResult.MakeGenericMethod(returnType).Invoke(null, new object[] { null! }); | |||
return; | |||
} | |||
context.AopContext.ReturnValue = null; | |||
return; | |||
} | |||
await InvokeNextAsync(context); | |||
} | |||
} | |||
} |
@@ -1,30 +0,0 @@ | |||
using AspectCore.DynamicProxy; | |||
using HealthMonitor.Core.Common; | |||
namespace HealthMonitor.Core.Pipeline.Aop.Update | |||
{ | |||
public class AssertValidUpdateHisValue : AopValueBase | |||
{ | |||
public override async Task Invoke(CacheInterceptorContext context) | |||
{ | |||
//方法需要存在参数用于生成缓存键和获取实体类型 | |||
if (context.AopContext.Parameters.Length < 2 || context.AopContext.Parameters[0] == null) | |||
{ | |||
throw new AssertValidException(); | |||
} | |||
var param = context.AopContext.Parameters[0]; | |||
var entityType = param.GetType(); | |||
context.IsAsyncMethod = context.AopContext.IsAsync(); | |||
context.EntityType = entityType; | |||
context.RequestId = context.AopContext.Parameters.Length > 2 ? context.AopContext.Parameters[2] + "" : ""; | |||
using (var scope = context.Logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = context.RequestId })) | |||
using (new CustomizeStopWatch($"更新历史aop[{entityType.Name}]", context.Logger)) | |||
{ | |||
await InvokeNextAsync(context); | |||
} | |||
} | |||
} | |||
} |
@@ -44,7 +44,7 @@ namespace HealthMonitor.WebApi.Controllers.Base | |||
/// <param name="requestId">关联服务标识</param> | |||
/// <returns></returns> | |||
[HttpGet] | |||
[QueryCacheInterceptor] | |||
//[QueryCacheInterceptor] | |||
public async virtual Task<T> GetById([Required] string id, [FromHeader] string requestId) | |||
{ | |||
AssertModelStateIsValid(); | |||
@@ -60,7 +60,7 @@ namespace HealthMonitor.WebApi.Controllers.Base | |||
/// <param name="requestId">关联服务标识</param> | |||
/// <returns></returns> | |||
[HttpPost] | |||
[QueryCacheInterceptor] | |||
//[QueryCacheInterceptor] | |||
public async virtual Task<T?> GetFirst([FromBody] GeneralParam conditions, [FromHeader] string requestId) | |||
{ | |||
AssertModelStateIsValid(); | |||
@@ -79,7 +79,7 @@ namespace HealthMonitor.WebApi.Controllers.Base | |||
/// <param name="requestId">关联服务标识</param> | |||
/// <returns></returns> | |||
[HttpPost] | |||
[QueryCacheInterceptor] | |||
//[QueryCacheInterceptor] | |||
public async virtual Task<IEnumerable<T>> GetList([FromBody] GeneralParam conditions, [FromHeader] string requestId) | |||
{ | |||
AssertModelStateIsValid(); | |||
@@ -96,7 +96,7 @@ namespace HealthMonitor.WebApi.Controllers.Base | |||
/// <param name="model"></param> | |||
/// <param name="requestId">关联服务标识</param> | |||
[HttpPost] | |||
[InsertCacheInterceptor] | |||
//[InsertCacheInterceptor] | |||
public virtual void Add([FromBody] T model, [FromHeader] string requestId) | |||
{ | |||
AssertModelStateIsValid(model); | |||
@@ -117,7 +117,7 @@ namespace HealthMonitor.WebApi.Controllers.Base | |||
/// <param name="model"></param> | |||
/// <param name="requestId">关联服务标识</param> | |||
[HttpPut] | |||
[UpdateCacheInterceptor] | |||
//[UpdateCacheInterceptor] | |||
public virtual void Update([FromBody] T model, [FromHeader] string requestId) | |||
{ | |||
AssertModelStateIsValid(model); | |||
@@ -138,7 +138,7 @@ namespace HealthMonitor.WebApi.Controllers.Base | |||
/// <param name="model"></param> | |||
/// <param name="requestId">关联服务标识</param> | |||
[HttpDelete] | |||
[DeleteCacheInterceptor] | |||
// [DeleteCacheInterceptor] | |||
public virtual void Delete([FromBody] T model, [FromHeader] string requestId) | |||
{ | |||
//删除操作不需要验证模型的有效性 | |||
@@ -66,33 +66,33 @@ namespace HealthMonitor.WebApi.Controllers.Base | |||
return await _dataAccessor.GetByIDAsync<T>(id); | |||
} | |||
/// <summary> | |||
/// 通过查询条件,获取符合条件的第一个实体 | |||
/// </summary> | |||
/// <param name="conditions"></param> | |||
/// <param name="requestId">关联服务标识</param> | |||
/// <returns></returns> | |||
//[HttpPost] | |||
// //[QueryCacheInterceptor] | |||
// public async virtual Task<T?> GetFirst([FromBody] GeneralParam conditions, [FromHeader] string requestId) | |||
//{ | |||
// AssertModelStateIsValid(); | |||
/// <summary> | |||
/// 通过查询条件,获取符合条件的第一个实体 | |||
/// </summary> | |||
/// <param name="conditions"></param> | |||
/// <param name="requestId">关联服务标识</param> | |||
/// <returns></returns> | |||
[HttpPost] | |||
// var parser = new QueryExpressionParser<T>(); | |||
// var expression = parser.ParserConditions(conditions.Filters!); | |||
// var list = await _dataAccessor.GetMany(expression).OrderConditions(conditions.OrderBys!).Take(1).ToListAsync(); | |||
//[QueryCacheInterceptor] | |||
public async virtual Task<T?> GetFirst([FromBody] GeneralParam conditions, [FromHeader] string requestId) | |||
{ | |||
AssertModelStateIsValid(); | |||
// return list.Count > 0 ? list[0] : null; | |||
//} | |||
var parser = new QueryExpressionParser<T>(); | |||
var expression = parser.ParserConditions(conditions.Filters!); | |||
var list = await _dataAccessor.GetMany(expression).OrderConditions(conditions.OrderBys!).Take(1).ToListAsync(); | |||
/// <summary> | |||
/// 获取实体列表(只提取符合条件的前100条记录) | |||
/// </summary> | |||
/// <param name="conditions"></param> | |||
/// <param name="requestId">关联服务标识</param> | |||
/// <returns></returns> | |||
[HttpPost] | |||
return list.Count > 0 ? list[0] : null; | |||
} | |||
/// <summary> | |||
/// 获取实体列表(只提取符合条件的前100条记录) | |||
/// </summary> | |||
/// <param name="conditions"></param> | |||
/// <param name="requestId">关联服务标识</param> | |||
/// <returns></returns> | |||
[HttpPost] | |||
//[QueryCacheInterceptor] | |||
public async virtual Task<PageData<T>> GetPageList([FromBody] Paging page, [FromHeader] string requestId) | |||
@@ -110,39 +110,9 @@ namespace HealthMonitor.WebApi.Controllers.Base | |||
public async virtual Task<IEnumerable<T>> GetList([FromBody] GeneralParam conditions, [FromHeader] string requestId) | |||
{ | |||
/** | |||
* { | |||
"filters": [ | |||
{ | |||
"key": "id", | |||
"value": "aaa", | |||
"valueType": 7, | |||
"operator": 0 | |||
} | |||
], | |||
"orderBys": [ | |||
{ | |||
"key": "id", | |||
"isDesc": true | |||
} | |||
] | |||
} | |||
* | |||
* | |||
* | |||
*/ | |||
AssertModelStateIsValid(); | |||
var parser = new QueryExpressionParser<T>(); | |||
var expression = parser.ParserConditions(conditions.Filters!); | |||
var aa = conditions.Filters!; | |||
var cc = await _dataAccessor.GetMany(expression).ToListAsync(); | |||
var dd = conditions.OrderBys!; | |||
var list = await _dataAccessor.GetMany(expression).OrderConditions(conditions.OrderBys!).Take(100).ToListAsync(); | |||
return list; | |||