diff --git a/HealthMonitor.Core/Aop/QueryCacheInterceptorAttribute.cs b/HealthMonitor.Core/Aop/QueryCacheInterceptorAttribute.cs index 48383d9..b8ffc1a 100644 --- a/HealthMonitor.Core/Aop/QueryCacheInterceptorAttribute.cs +++ b/HealthMonitor.Core/Aop/QueryCacheInterceptorAttribute.cs @@ -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); diff --git a/HealthMonitor.Core/Class1.cs b/HealthMonitor.Core/Class1.cs deleted file mode 100644 index 66f02c1..0000000 --- a/HealthMonitor.Core/Class1.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace HealthMonitor.Core -{ - public class Class1 - { - - } -} \ No newline at end of file diff --git a/HealthMonitor.Core/Operator/IHealthMonitorOperatorManager.cs b/HealthMonitor.Core/Operator/IHealthMonitorOperatorManager.cs index 33ded13..07d85b4 100644 --- a/HealthMonitor.Core/Operator/IHealthMonitorOperatorManager.cs +++ b/HealthMonitor.Core/Operator/IHealthMonitorOperatorManager.cs @@ -1,4 +1,7 @@ -namespace HealthMonitor.Core.Operator +using HealthMonitor.Core.Common; +using HealthMonitor.Util.Common.Operator; + +namespace HealthMonitor.Core.Operator { /// /// HealthMonitor数据库的批量操作缓存管理器 diff --git a/HealthMonitor.Core/Pipeline/Aop/Delete/AssertValidDeleteHisValue.cs b/HealthMonitor.Core/Pipeline/Aop/Delete/AssertValidDeleteHisValue.cs deleted file mode 100644 index a99f8aa..0000000 --- a/HealthMonitor.Core/Pipeline/Aop/Delete/AssertValidDeleteHisValue.cs +++ /dev/null @@ -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 { ["RequestId"] = context.RequestId })) - using (new CustomizeStopWatch($"删除历史aop[{entityType.Name}]", context.Logger)) - { - await InvokeNextAsync(context); - } - } - } -} diff --git a/HealthMonitor.Core/Pipeline/Aop/Delete/DeleteEntityCacheHisValue.cs b/HealthMonitor.Core/Pipeline/Aop/Delete/DeleteEntityCacheHisValue.cs deleted file mode 100644 index 71cd91c..0000000 --- a/HealthMonitor.Core/Pipeline/Aop/Delete/DeleteEntityCacheHisValue.cs +++ /dev/null @@ -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(); - 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); - } - } -} diff --git a/HealthMonitor.Core/Pipeline/Aop/Query/AssertValidQueryHisValue.cs b/HealthMonitor.Core/Pipeline/Aop/Query/AssertValidQueryHisValue.cs deleted file mode 100644 index fb6e012..0000000 --- a/HealthMonitor.Core/Pipeline/Aop/Query/AssertValidQueryHisValue.cs +++ /dev/null @@ -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 { ["RequestId"] = context.RequestId })) - using (new CustomizeStopWatch($"查询历史aop[{entityType?.Name}]", context.Logger)) - { - await InvokeNextAsync(context); - } - } - } -} diff --git a/HealthMonitor.Core/Pipeline/Aop/Query/GetOrInsertEntityCacheHisValue.cs b/HealthMonitor.Core/Pipeline/Aop/Query/GetOrInsertEntityCacheHisValue.cs deleted file mode 100644 index edebd70..0000000 --- a/HealthMonitor.Core/Pipeline/Aop/Query/GetOrInsertEntityCacheHisValue.cs +++ /dev/null @@ -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(); - 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.Result)).GetValue(context.ReturnValue); - } - else - { - returnValue = context.AopContext.ReturnValue; - } - cacheHandler.SetEntityCache(key, returnValue, isEnumerable); - } - } -} diff --git a/HealthMonitor.Core/Pipeline/Aop/Query/TryGetRefManagerValue.cs b/HealthMonitor.Core/Pipeline/Aop/Query/TryGetRefManagerValue.cs new file mode 100644 index 0000000..bd4d778 --- /dev/null +++ b/HealthMonitor.Core/Pipeline/Aop/Query/TryGetRefManagerValue.cs @@ -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(); + //else if (entityType.IsSubclassOf(typeof(TelpoCommonEntityBase))) operatorManager = context.AopContext.ServiceProvider.GetService(); + + 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); + } + } +} diff --git a/HealthMonitor.Core/Pipeline/Aop/Update/AssertValidUpdateHisValue.cs b/HealthMonitor.Core/Pipeline/Aop/Update/AssertValidUpdateHisValue.cs deleted file mode 100644 index 3574463..0000000 --- a/HealthMonitor.Core/Pipeline/Aop/Update/AssertValidUpdateHisValue.cs +++ /dev/null @@ -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 { ["RequestId"] = context.RequestId })) - using (new CustomizeStopWatch($"更新历史aop[{entityType.Name}]", context.Logger)) - { - await InvokeNextAsync(context); - } - } - } -} diff --git a/HealthMonitor.WebApi/Controllers/Base/GpsCardControllerBase.cs b/HealthMonitor.WebApi/Controllers/Base/GpsCardControllerBase.cs index d603ee5..eee64a0 100644 --- a/HealthMonitor.WebApi/Controllers/Base/GpsCardControllerBase.cs +++ b/HealthMonitor.WebApi/Controllers/Base/GpsCardControllerBase.cs @@ -44,7 +44,7 @@ namespace HealthMonitor.WebApi.Controllers.Base /// 关联服务标识 /// [HttpGet] - [QueryCacheInterceptor] + //[QueryCacheInterceptor] public async virtual Task GetById([Required] string id, [FromHeader] string requestId) { AssertModelStateIsValid(); @@ -60,7 +60,7 @@ namespace HealthMonitor.WebApi.Controllers.Base /// 关联服务标识 /// [HttpPost] - [QueryCacheInterceptor] + //[QueryCacheInterceptor] public async virtual Task GetFirst([FromBody] GeneralParam conditions, [FromHeader] string requestId) { AssertModelStateIsValid(); @@ -79,7 +79,7 @@ namespace HealthMonitor.WebApi.Controllers.Base /// 关联服务标识 /// [HttpPost] - [QueryCacheInterceptor] + //[QueryCacheInterceptor] public async virtual Task> GetList([FromBody] GeneralParam conditions, [FromHeader] string requestId) { AssertModelStateIsValid(); @@ -96,7 +96,7 @@ namespace HealthMonitor.WebApi.Controllers.Base /// /// 关联服务标识 [HttpPost] - [InsertCacheInterceptor] + //[InsertCacheInterceptor] public virtual void Add([FromBody] T model, [FromHeader] string requestId) { AssertModelStateIsValid(model); @@ -117,7 +117,7 @@ namespace HealthMonitor.WebApi.Controllers.Base /// /// 关联服务标识 [HttpPut] - [UpdateCacheInterceptor] + //[UpdateCacheInterceptor] public virtual void Update([FromBody] T model, [FromHeader] string requestId) { AssertModelStateIsValid(model); @@ -138,7 +138,7 @@ namespace HealthMonitor.WebApi.Controllers.Base /// /// 关联服务标识 [HttpDelete] - [DeleteCacheInterceptor] + // [DeleteCacheInterceptor] public virtual void Delete([FromBody] T model, [FromHeader] string requestId) { //删除操作不需要验证模型的有效性 diff --git a/HealthMonitor.WebApi/Controllers/Base/HealthMonitorControllerBase.cs b/HealthMonitor.WebApi/Controllers/Base/HealthMonitorControllerBase.cs index 9937449..61e372f 100644 --- a/HealthMonitor.WebApi/Controllers/Base/HealthMonitorControllerBase.cs +++ b/HealthMonitor.WebApi/Controllers/Base/HealthMonitorControllerBase.cs @@ -66,33 +66,33 @@ namespace HealthMonitor.WebApi.Controllers.Base return await _dataAccessor.GetByIDAsync(id); } - /// - /// 通过查询条件,获取符合条件的第一个实体 - /// - /// - /// 关联服务标识 - /// - //[HttpPost] - - // //[QueryCacheInterceptor] - // public async virtual Task GetFirst([FromBody] GeneralParam conditions, [FromHeader] string requestId) - //{ - // AssertModelStateIsValid(); + /// + /// 通过查询条件,获取符合条件的第一个实体 + /// + /// + /// 关联服务标识 + /// + [HttpPost] - // var parser = new QueryExpressionParser(); - // var expression = parser.ParserConditions(conditions.Filters!); - // var list = await _dataAccessor.GetMany(expression).OrderConditions(conditions.OrderBys!).Take(1).ToListAsync(); + //[QueryCacheInterceptor] + public async virtual Task GetFirst([FromBody] GeneralParam conditions, [FromHeader] string requestId) + { + AssertModelStateIsValid(); - // return list.Count > 0 ? list[0] : null; - //} + var parser = new QueryExpressionParser(); + var expression = parser.ParserConditions(conditions.Filters!); + var list = await _dataAccessor.GetMany(expression).OrderConditions(conditions.OrderBys!).Take(1).ToListAsync(); - /// - /// 获取实体列表(只提取符合条件的前100条记录) - /// - /// - /// 关联服务标识 - /// - [HttpPost] + return list.Count > 0 ? list[0] : null; + } + + /// + /// 获取实体列表(只提取符合条件的前100条记录) + /// + /// + /// 关联服务标识 + /// + [HttpPost] //[QueryCacheInterceptor] public async virtual Task> GetPageList([FromBody] Paging page, [FromHeader] string requestId) @@ -110,39 +110,9 @@ namespace HealthMonitor.WebApi.Controllers.Base public async virtual Task> 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(); - - - - 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;