using FreeRedis; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus; using Yi.Framework.Bbs.Domain.Shared.Caches; using Yi.Framework.Bbs.Domain.Shared.Etos; namespace Yi.Framework.Bbs.Application.Extensions; /// /// 访问日志中间件 /// 并发最高,采用缓存,默认10分钟才会真正操作一次数据库 /// 需考虑一致性问题,又不能上锁影响性能 /// public class AccessLogMiddleware : IMiddleware, ITransientDependency { private static int _accessLogNumber = 0; internal static void ResetAccessLogNumber() { _accessLogNumber = 0; } internal static int GetAccessLogNumber() { return _accessLogNumber; } public async Task InvokeAsync(HttpContext context, RequestDelegate next) { await next(context); Interlocked.Increment(ref _accessLogNumber); } } public class AccessLogResetEventHandler : ILocalEventHandler, ITransientDependency { /// /// 缓存前缀 /// private string CacheKeyPrefix => LazyServiceProvider.LazyGetRequiredService>() .Value.KeyPrefix; /// /// 使用懒加载防止报错 /// private IRedisClient RedisClient => LazyServiceProvider.LazyGetRequiredService(); /// /// 属性注入 /// public IAbpLazyServiceProvider LazyServiceProvider { get; set; } private bool EnableRedisCache { get { var redisEnabled = LazyServiceProvider.LazyGetRequiredService()["Redis:IsEnabled"]; return redisEnabled.IsNullOrEmpty() || bool.Parse(redisEnabled); } } //该事件由job定时10秒触发 public async Task HandleEventAsync(AccessLogResetArgs eventData) { if (EnableRedisCache) { //分布式锁 if (await RedisClient.SetNxAsync("AccessLogLock", true, TimeSpan.FromSeconds(5))) { //自增长数 var incrNumber = AccessLogMiddleware.GetAccessLogNumber(); //立即重置,开始计算,方式丢失 AccessLogMiddleware.ResetAccessLogNumber(); if (incrNumber > 0) { await RedisClient.IncrByAsync( $"{CacheKeyPrefix}{AccessLogCacheConst.Key}:{DateTime.Now.Date:yyyyMMdd}", incrNumber); } } } } }