241 lines
8.8 KiB
Markdown
241 lines
8.8 KiB
Markdown
# 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 基类
|
||
```csharp
|
||
// 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
|
||
```csharp
|
||
// 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 接口
|
||
```csharp
|
||
// 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 实现
|
||
```csharp
|
||
// 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 模块
|
||
```csharp
|
||
// 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
|
||
```csharp
|
||
// Mappings/MappingConfig.cs
|
||
public static class MappingConfig
|
||
{
|
||
public static void Configure();
|
||
}
|
||
```
|
||
|
||
### HoneyBox.Api 组件
|
||
|
||
#### GlobalExceptionFilter
|
||
```csharp
|
||
// Filters/GlobalExceptionFilter.cs
|
||
public class GlobalExceptionFilter : IExceptionFilter
|
||
{
|
||
public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger);
|
||
public void OnException(ExceptionContext context);
|
||
}
|
||
```
|
||
|
||
#### HealthController
|
||
```csharp
|
||
// 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
|
||
|
||
### 健康检查响应模型
|
||
```csharp
|
||
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 接口返回格式:
|
||
```json
|
||
{
|
||
"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)
|