|
| 1 | +# StarBlog 架构重构 Code Review 报告 |
| 2 | + |
| 3 | +**日期**: 2026-02-13 |
| 4 | +**审查范围**: `StarBlog.Api`, `StarBlog.Application` 及其依赖项 |
| 5 | +**审查者**: 资深架构师 AI |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +## 1. 总体概述 |
| 10 | +本次重构成功地将业务逻辑从 Web 层剥离到了 Application 层,形成了清晰的 **N-Tier(多层)架构**。项目结构整洁,职责划分基本合理,但也存在一些典型的架构耦合问题和代码异味(Code Smell)。 |
| 11 | + |
| 12 | +## 2. 架构与分层设计 |
| 13 | + |
| 14 | +### ✅ 优点 |
| 15 | +1. **清晰的依赖方向**:遵循 `Api -> Application -> Data` 的引用链,符合分层原则。 |
| 16 | +2. **Application 层职责明确**: |
| 17 | + * **Services**(如 `PostService`)承载了核心业务逻辑(Markdown 解析、图片处理、数据存取)。 |
| 18 | + * **Api**(Controllers)保持轻量,仅负责 HTTP 协议处理、参数解析和响应封装。 |
| 19 | +3. **混合配置管理**:`ConfigService` 实现了“数据库覆盖配置文件”的策略,既保留了 `appsettings.json` 的灵活性,又支持运行时修改配置。 |
| 20 | + |
| 21 | +### ⚠️ 改进点 |
| 22 | +* **Application 层对 Web 框架的泄漏**: |
| 23 | + * `StarBlog.Application` 引用了 `Microsoft.AspNetCore.App` 框架。 |
| 24 | + * **影响**:这使得应用层包含了大量 Web 特有的 API,模糊了边界,容易导致代码不小心依赖 `HttpContext`。 |
| 25 | + |
| 26 | +--- |
| 27 | + |
| 28 | +## 3. 关键问题 (Critical Issues) |
| 29 | + |
| 30 | +### 3.1. `MessageService` 强耦合 `HttpContext` |
| 31 | +* **位置**:[MessageService.cs](../src/StarBlog.Application/Contrib/SiteMessage/MessageService.cs) |
| 32 | +* **问题**:该服务直接注入 `IHttpContextAccessor` 并依赖 `Session` 存储消息。 |
| 33 | + ```csharp |
| 34 | + if (HttpContext == null) { |
| 35 | + throw new Exception("There is no active HttpContext..."); |
| 36 | + } |
| 37 | + ``` |
| 38 | +* **风险**:导致该服务**无法在非 Web 环境下运行**(如后台任务 `IHostedService`、单元测试、或控制台工具)。 |
| 39 | +* **建议**: |
| 40 | + * **方案 A (推荐)**:定义 `IMessageStore` 接口,Web 层实现 `SessionMessageStore`,后台任务实现 `MemoryMessageStore`。 |
| 41 | + * **方案 B**:将此服务移动到 `StarBlog.Web` 或 `StarBlog.Api` 层,因为它本质上是 UI 交互的一部分。 |
| 42 | + |
| 43 | +### 3.2. API 直接暴露数据库实体 (Domain Entity Leakage) |
| 44 | +* **位置**:[PostService.cs](../src/StarBlog.Application/Services/PostService.cs) 及相关 Controllers。 |
| 45 | +* **问题**:`GetById`、`GetPagedList` 等方法直接返回 `Post` 实体(定义在 Data 层)。 |
| 46 | + ```csharp |
| 47 | + public async Task<Post?> GetById(string id) { ... } |
| 48 | + ``` |
| 49 | +* **风险**: |
| 50 | + * **契约不稳**:数据库表结构的变化会直接破坏 API 契约(Breaking Change)。 |
| 51 | + * **过度暴露**:可能意外暴露不应公开的字段(如 `IsDeleted`、内部状态字段等)。 |
| 52 | + * **逻辑混杂**:`PostService` 中直接修改实体内容(`post.Content = ...`)用于前端展示,污染了实体本身的数据纯度。 |
| 53 | +* **建议**:引入 `PostDto` 或 `PostViewModel`,使用 `AutoMapper` 在 Service 层或 Controller 层完成映射。 |
| 54 | + |
| 55 | +--- |
| 56 | + |
| 57 | +## 4. 代码质量与最佳实践 |
| 58 | + |
| 59 | +### 4.1. 异步 IO 的隐患 |
| 60 | +* **位置**:`PostService.cs` -> `MdExternalUrlDownloadAsync` |
| 61 | +* **观察**:在保存文章时,会同步等待外部图片下载。 |
| 62 | +* **建议**:建议引入后台任务队列(如 `Channel<T>` 或 Hangfire),将“图片本地化”作为后台作业异步处理,避免阻塞文章保存操作。 |
| 63 | + |
| 64 | +### 4.2. 混合 ORM 的使用 |
| 65 | +* **观察**:项目同时使用了 `FreeSql` (业务数据) 和 `EF Core` (SQLite 日志)。 |
| 66 | +* **评价**:增加了维护成本和认知负担(开发人员需掌握两套查询语法)。若非为了兼容旧代码,建议逐步统一。 |
| 67 | + |
| 68 | +--- |
| 69 | + |
| 70 | +## 5. 总结与行动指南 |
| 71 | + |
| 72 | +**综合评分**: **B+** |
| 73 | +重构方向正确,代码组织良好,但在**层级隔离**和**API 契约设计**上仍有提升空间。 |
| 74 | + |
| 75 | +**接下来的行动建议:** |
| 76 | + |
| 77 | +1. **Refactor `MessageService`**:优先将其解耦,确保 Application 层的纯洁性。 |
| 78 | +2. **Introduce DTOs**:从最核心的 `Post` 接口开始,使用 ViewModel 隔离数据库实体。 |
| 79 | +3. **Optimize Image Downloading**:改为后台队列处理图片下载。 |
0 commit comments