namespace Dpz.Core.Service.RepositoryServiceImpl;
public class BlockService(IRepository<Block> repository, IMapper mapper) : IBlockService
{
/// <inheritdoc />
public async Task SaveBlockAsync(Block block)
{
var entity = await repository
.SearchFor(x =>
x.RequestMethod == block.RequestMethod && x.RequestPath == block.RequestPath
)
.FirstOrDefaultAsync();
if (entity != null)
{
var updates = new List<UpdateDefinition<Block>>
{
Builders<Block>.Update.Inc(x => x.AccessCount, 1),
};
var pushIpAddresses = block.IpAddresses.Except(entity.IpAddresses).ToList();
if (pushIpAddresses.Count > 0)
{
updates.Add(Builders<Block>.Update.PushEach(x => x.IpAddresses, pushIpAddresses));
}
var pushUserAgents = block.UserAgents.Except(entity.UserAgents).ToList();
if (pushUserAgents.Count > 0)
{
updates.Add(Builders<Block>.Update.PushEach(x => x.UserAgents, pushUserAgents));
}
await repository.UpdateAsync(
x => x.Id == entity.Id,
Builders<Block>.Update.Combine(updates)
);
return;
}
if (block.AccessCount <= 0)
{
block.AccessCount = 1;
}
await repository.InsertAsync(block);
}
/// <inheritdoc />
public async Task IncrementCountAsync(string method, string requestPath)
{
var block = await repository
.SearchFor(x => x.RequestMethod == method && x.RequestPath == requestPath)
.FirstOrDefaultAsync();
if (block == null)
{
await SaveBlockAsync(new Block { RequestMethod = method, RequestPath = requestPath });
return;
}
var update = Builders<Block>.Update.Inc(x => x.AccessCount, 1);
await repository.UpdateAsync(x => x.Id == block.Id, update);
}
/// <inheritdoc />
[Cache(ExpirationSeconds = 3 * ExpirationTime.Hour)]
public async Task<List<VmBlock>> GetBlocksAsync(int? minAccess = null)
{
var minAccessValue = minAccess ?? 0;
var list = await repository.SearchFor(x => x.AccessCount >= minAccessValue).ToListAsync();
return mapper.Map<List<VmBlock>>(list);
}
/// <inheritdoc />
[InvalidateCache(Methods = [nameof(GetBlocksAsync)])]
public async Task DeleteAsync(string id, CancellationToken cancellationToken = default)
{
if (!ObjectId.TryParse(id, out var oid))
{
return;
}
await repository.DeleteAsync(oid, cancellationToken);
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
代码解释
这是一个名为 BlockService 的服务类,用于管理"阻止记录"(Block)的业务逻辑。该类实现了 IBlockService 接口,主要用于跟踪和管理HTTP请求的访问统计信息。
类结构
public class BlockService(IRepository<Block> repository, IMapper mapper) : IBlockService
- 使用了 C# 12 的主构造函数语法
- 依赖注入两个服务:
IRepository<Block>:数据仓储接口,用于数据库操作IMapper:对象映射器(通常是 AutoMapper)
核心方法解析
1. SaveBlockAsync(Block block)
功能:保存或更新阻止记录
逻辑流程:
- 根据请求方法和路径查找是否存在记录
- 如果存在:
- 访问计数 +1
- 合并新的 IP 地址(去重)
- 合并新的 User-Agent(去重)
- 执行批量更新操作
- 如果不存在:
- 初始化访问计数为1(如果未设置)
- 插入新记录
关键技术点:
- 使用 MongoDB 的
Update构建器 Inc:原子递增操作PushEach:批量追加数组元素Except:LINQ 集合差集运算
2. IncrementCountAsync(string method, string requestPath)
功能:增加指定请求路径的访问计数
逻辑流程:
- 查找匹配的记录
- 如果不存在,创建新记录
- 如果存在,访问计数 +1
3. GetBlocksAsync(int? minAccess = null)
功能:获取阻止记录列表(支持最小访问次数过滤)
特点:
[Cache(ExpirationSeconds = 3 * ExpirationTime.Hour)]:结果缓存3小时- 使用 AutoMapper 映射到视图模型
VmBlock - 默认最小访问次数为0
4. DeleteAsync(string id, CancellationToken cancellationToken)
功能:删除指定ID的记录
特点:
[InvalidateCache(Methods = [nameof(GetBlocksAsync)])]:删除时使GetBlocksAsync的缓存失效- 验证
ObjectId格式 - 支持取消令牌
应用场景
这个服务通常用于:
- 请求限流/防护:记录频繁访问的IP和请求
- 安全审计:跟踪可疑请求模式
- 访问统计:分析API使用情况
技术亮点
- 原子操作:使用 MongoDB 的原子更新避免并发问题
- 性能优化:
- 缓存查询结果
- 批量更新操作
- 去重逻辑减少存储
- 缓存策略:读缓存 + 写失效模式
- 异步编程:全异步方法提升性能
AI 正在分析代码…
评论加载中...