HaniBlindBox/.kiro/specs/api-infrastructure/design.md
2026-01-02 15:46:56 +08:00

8.8 KiB
Raw Blame History

Design Document

Overview

本设计文档描述 HoneyBox 抽奖系统 .NET 8 Web API 项目基础架构的技术实现方案。采用四层架构设计,使用 Autofac 进行依赖注入Mapster 进行对象映射Serilog 进行日志记录Redis 进行分布式缓存。

Architecture

┌─────────────────────────────────────────────────────────────┐
│                      HoneyBox.Api                           │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
│  │ Controllers │  │   Filters   │  │    Middlewares      │  │
│  └─────────────┘  └─────────────┘  └─────────────────────┘  │
└─────────────────────────────────────────────────────────────┘
                              │
              ┌───────────────┴───────────────┐
              ▼                               ▼
┌─────────────────────────┐     ┌─────────────────────────────┐
│     HoneyBox.Core       │     │      HoneyBox.Model         │
│  ┌─────────────────┐    │     │  ┌─────────────────────┐    │
│  │    Services     │    │     │  │      Entities       │    │
│  ├─────────────────┤    │     │  ├─────────────────────┤    │
│  │   Interfaces    │    │     │  │       Models        │    │
│  ├─────────────────┤    │     │  ├─────────────────────┤    │
│  │    Mappings     │    │     │  │        Data         │    │
│  └─────────────────┘    │     │  ├─────────────────────┤    │
└─────────────────────────┘     │  │        Base         │    │
              │                 │  └─────────────────────┘    │
              ▼                 └─────────────────────────────┘
┌─────────────────────────┐
│ HoneyBox.Infrastructure │
│  ┌─────────────────┐    │
│  │      Cache      │    │
│  ├─────────────────┤    │
│  │    External     │    │
│  ├─────────────────┤    │
│  │     Modules     │    │
│  └─────────────────┘    │
└─────────────────────────┘

依赖关系

Api → Core, Model
Core → Model, Infrastructure
Infrastructure → 无依赖
Model → 无依赖

Components and Interfaces

HoneyBox.Model 组件

ApiResponse 基类

// Base/ApiResponse.cs
public class ApiResponse
{
    public int Code { get; set; }
    public string Msg { get; set; } = string.Empty;
    
    public static ApiResponse Success(string msg = "success");
    public static ApiResponse Fail(string msg, int code = -1);
}

public class ApiResponse<T> : ApiResponse
{
    public T? Data { get; set; }
    
    public static ApiResponse<T> Success(T data, string msg = "success");
    public new static ApiResponse<T> Fail(string msg, int code = -1);
}

HoneyBoxDbContext

// Data/HoneyBoxDbContext.cs
public partial class HoneyBoxDbContext : DbContext
{
    public HoneyBoxDbContext(DbContextOptions<HoneyBoxDbContext> options);
    
    public virtual DbSet<User> Users { get; set; }
    public virtual DbSet<Goods> Goods { get; set; }
    public virtual DbSet<Order> Orders { get; set; }
    // ... 其他 DbSet
}

HoneyBox.Infrastructure 组件

ICacheService 接口

// Cache/ICacheService.cs
public interface ICacheService
{
    Task<T?> GetAsync<T>(string key);
    Task SetAsync<T>(string key, T value, TimeSpan? expiry = null);
    Task RemoveAsync(string key);
    Task<bool> ExistsAsync(string key);
    Task<bool> IsConnectedAsync();
}

RedisCacheService 实现

// Cache/RedisCacheService.cs
public class RedisCacheService : ICacheService
{
    private readonly IDatabase _database;
    private readonly ConnectionMultiplexer _connection;
    
    public RedisCacheService(IConfiguration configuration);
    public Task<T?> GetAsync<T>(string key);
    public Task SetAsync<T>(string key, T value, TimeSpan? expiry = null);
    public Task RemoveAsync(string key);
    public Task<bool> ExistsAsync(string key);
    public Task<bool> IsConnectedAsync();
}

Autofac 模块

// Modules/ServiceModule.cs
public class ServiceModule : Module
{
    protected override void Load(ContainerBuilder builder);
}

// Modules/InfrastructureModule.cs
public class InfrastructureModule : Module
{
    protected override void Load(ContainerBuilder builder);
}

HoneyBox.Core 组件

MappingConfig

// Mappings/MappingConfig.cs
public static class MappingConfig
{
    public static void Configure();
}

HoneyBox.Api 组件

GlobalExceptionFilter

// Filters/GlobalExceptionFilter.cs
public class GlobalExceptionFilter : IExceptionFilter
{
    public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger);
    public void OnException(ExceptionContext context);
}

HealthController

// Controllers/HealthController.cs
[ApiController]
[Route("api/[controller]")]
public class HealthController : ControllerBase
{
    public HealthController(HoneyBoxDbContext dbContext, ICacheService cacheService);
    
    [HttpGet]
    public Task<ApiResponse<HealthCheckData>> GetHealth();
}

Data Models

健康检查响应模型

public class HealthCheckData
{
    public string Status { get; set; } = string.Empty;
    public string Database { get; set; } = string.Empty;
    public string Redis { get; set; } = string.Empty;
    public DateTime Timestamp { get; set; }
}

统一响应格式

所有 API 接口返回格式:

{
  "code": 0,
  "msg": "success",
  "data": { ... }
}

Correctness Properties

A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.

由于本阶段主要是基础架构搭建,大部分验收标准是结构性检查(文件是否存在、配置是否正确),属于示例测试而非属性测试。以下是可以进行属性测试的场景:

Property 1: ApiResponse 格式一致性

For any API 响应,返回的 JSON 结构 SHALL 始终包含 code、msg 字段,当有数据时包含 data 字段 Validates: Requirements 6.4

Property 2: 缓存读写一致性

For any 缓存键值对,写入后立即读取 SHALL 返回相同的值 Validates: Requirements 3.5

Error Handling

全局异常处理策略

  1. 所有未捕获异常由 GlobalExceptionFilter 统一处理
  2. 异常信息记录到日志Serilog
  3. 返回统一格式的错误响应:{ "code": 500, "msg": "服务器内部错误" }
  4. 开发环境可返回详细错误信息,生产环境隐藏敏感信息

连接失败处理

  1. 数据库连接失败:健康检查返回 Database: "Disconnected"
  2. Redis 连接失败:健康检查返回 Redis: "Disconnected",但不影响应用启动

Testing Strategy

验证方式

由于本阶段是基础架构搭建,主要通过以下方式验证:

  1. 编译验证dotnet build 确保项目能正常编译
  2. 运行验证:启动应用,访问 Swagger 文档
  3. 健康检查验证:调用 /api/health 接口验证数据库和 Redis 连接
  4. 日志验证:检查控制台和日志文件输出

手动测试清单

  • 解决方案能正常编译
  • 应用能正常启动
  • Swagger 文档可访问 (http://localhost:5000/swagger)
  • 健康检查接口返回正确格式
  • 日志输出到控制台
  • 日志输出到文件 (logs/log-*.txt)