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. 根据请求方法和路径查找是否存在记录
  2. 如果存在
    • 访问计数 +1
    • 合并新的 IP 地址(去重)
    • 合并新的 User-Agent(去重)
    • 执行批量更新操作
  3. 如果不存在
    • 初始化访问计数为1(如果未设置)
    • 插入新记录

关键技术点

  • 使用 MongoDB 的 Update 构建器
  • Inc:原子递增操作
  • PushEach:批量追加数组元素
  • Except:LINQ 集合差集运算

2. IncrementCountAsync(string method, string requestPath)

功能:增加指定请求路径的访问计数

逻辑流程

  1. 查找匹配的记录
  2. 如果不存在,创建新记录
  3. 如果存在,访问计数 +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使用情况

技术亮点

  1. 原子操作:使用 MongoDB 的原子更新避免并发问题
  2. 性能优化
    • 缓存查询结果
    • 批量更新操作
    • 去重逻辑减少存储
  3. 缓存策略:读缓存 + 写失效模式
  4. 异步编程:全异步方法提升性能
评论加载中...