# WIDESEA WMS 系统重构计划
## 项目概况
### 项目基本信息
- **项目名称**: WIDESEA_WMSServer 仓库管理系统
- **项目类型**: ASP.NET Core 6.0 Web API
- **代码规模**: 351个C#文件,约912行代码
- **模块数量**: 20个模块
- **架构模式**: 分层架构 (Model-DTO-Repository-Service-API)
### 项目结构
```
WIDESEA_WMSServer/ # 主API项目
WIDESEA_Model/ # 数据模型层
WIDESEA_DTO/ # 数据传输对象层
WIDESEA_Core/ # 核心基础架构层
├── BaseRepository/ # 数据仓储层
├── BaseServices/ # 基础服务层
├── DB/ # 数据库配置
├── Helper/ # 辅助工具类
├── Utilities/ # 工具类
├── Middlewares/ # 中间件
└── ...
WIDESEA_Common/ # 公共枚举和常量
WIDESEA_BasicService/ # 基础信息服务实现
WIDESEA_InboundService/ # 入库服务实现
WIDESEA_OutboundService/ # 出库服务实现
WIDESEA_StockService/ # 库存服务实现
WIDESEA_CheckService/ # 盘点服务实现
WIDESEA_SystemService/ # 系统服务实现
WIDESEA_RecordService/ # 记录服务实现
WIDESEA_TaskInfoService/ # 任务信息服务实现
```
---
## 发现的问题清单
### 一、高优先级问题 (P0 - 立即处理)
#### 1.1 空异常捕获块 (严重)
**问题描述**: 多处代码中存在空的catch块,会隐藏异常导致难以调试
**影响范围**: 7个文件
**示例位置**:
- `WIDESEA_Core/BaseServices/ServiceBase.cs:114` - 空catch块
- `WIDESEA_Core/Helper/ObjectExtension.cs:51-54` - 空catch块
- `WIDESEA_Core/DB/BaseDBConfig.cs:32-34` - 空catch块
- `WIDESEA_Core/BaseModels/PageDataOptions.cs` - 空catch块
- `WIDESEA_Core/Middlewares/ApiLogMiddleware.cs` - 空catch块
- `WIDESEA_Core/Utilities/EntityProperties.cs` - 空catch块
- `WIDESEA_SystemService/Sys_MenuService.cs` - 空catch块
- `WIDESEA_SystemService/Sys_UserService.cs` - 空catch块
**重构建议**:
```csharp
// 不好的做法
try { ... } catch { }
// 好的做法
try
{
// 业务逻辑
}
catch (Exception ex)
{
_logger.LogError(ex, "操作失败");
throw;
}
```
**预估工作量**: 2人天
---
#### 1.2 命名规范错误 (严重)
**问题描述**: 关键实体类存在拼写错误
**影响范围**: 基础实体层
**示例位置**:
- `WIDESEA_Core/DB/Models/BaseEntity.cs:44` - `Creater` 应为 `Creator`
- 该拼写错误在数据库映射、序列化、导入导出等多处使用
**重构建议**:
1. 修正 `BaseEntity.Creater` 为 `Creator`
2. 添加数据库列别名映射保持兼容性
3. 全局搜索替换所有引用
**预估工作量**: 3人天
---
#### 1.3 无限循环线程风险 (严重)
**问题描述**: Logger类使用 `while(true)` 无限循环,缺乏取消机制
**影响位置**: `WIDESEA_Core/LogHelper/Logger.cs:32-66`
**重构建议**:
```csharp
// 使用CancellationToken替代while(true)
private readonly CancellationTokenSource _cts = new();
static async void StartWriteLog()
{
try
{
while (!_cts.IsCancellationRequested)
{
// 处理逻辑
await Task.Delay(5000, _cts.Token);
}
}
catch (OperationCanceledException)
{
// 正常取消
}
}
// 添加Dispose方法释放资源
public static void Dispose() => _cts.Cancel();
```
**预估工作量**: 1人天
---
#### 1.4 TODO注释未完成 (高)
**问题描述**: 代码中存在未完成的TODO注释
**影响范围**: 5个文件
**示例位置**:
- `WIDESEA_Core/Helper/HTTP/HttpClientHelper.cs:181,211,222` - TODO:日志记录
- `WIDESEA_WMSServer/Program.cs` - TODO项
**重构建议**: 完成所有TODO标记的功能或删除无用的TODO
**预估工作量**: 1人天
---
### 二、中优先级问题 (P1 - 近期处理)
#### 2.1 代码重复严重 (高)
**问题描述**: RepositoryBase和ServiceBase中存在大量重复代码
**RepositoryBase重复**:
- 同步方法与异步方法逻辑完全重复 (约50个方法)
- 示例: `QureyDataById` 和 `QureyDataByIdAsync` 只是调用异步版本
**ServiceBase重复**:
- CRUD操作代码重复
- 分页查询逻辑重复
- 导入导出逻辑重复
**重构建议**:
1. 使用源代码生成器自动生成异步方法
2. 提取公共逻辑到扩展方法
3. 使用Template Method模式减少重复
**预估工作量**: 5人天
---
#### 2.2 方法过长 (中)
**问题描述**: 单个方法行数过多,可读性差
**示例**:
- `ServiceBase.GetPageData()` - 43行
- `ServiceBase.ValidatePageOptions()` - 52行
- `ServiceBase.GetWhereExpression()` - 121行
- `ServiceBase.UpdateData()` - 63行
**重构建议**: 将大方法拆分为小方法,每个方法不超过20行
**预估工作量**: 4人天
---
#### 2.3 混用JSON序列化库 (中)
**问题描述**: 同时使用 Newtonsoft.Json 和 System.Text.Json
**影响范围**: 16个文件混用
**示例**:
- `HttpClientHelper.cs` 使用 Newtonsoft.Json
- `ServiceBase.cs` 使用 Newtonsoft.Json
- `Program.cs` 使用 System.Text.Json
**重构建议**: 统一使用 System.Text.Json (.NET Core官方推荐)
**预估工作量**: 3人日
---
#### 2.4 过度使用dynamic类型 (中)
**问题描述**: 大量使用dynamic,降低类型安全和IDE支持
**示例位置**:
- `Logger.cs:19,151-169` - 使用dynamic作为日志对象
- `BaseDBConfig.cs:57` - 使用dynamic接收数据库查询结果
**重构建议**:
```csharp
// 定义明确的日志实体
public class LogEntry
{
public DateTime BeginDate { get; set; }
public DateTime EndDate { get; set; }
public string RequestParam { get; set; }
public string ResponseParam { get; set; }
// ...
}
```
**预估工作量**: 2人天
---
#### 2.5 硬编码字符串和魔法数字 (中)
**问题描述**: 大量硬编码值,缺乏常量定义
**示例**:
- `Logger.cs:37` - 硬编码500 (批量插入大小)
- `Logger.cs:42` - 硬编码5000 (轮询间隔)
- `PDAController.cs:79` - 硬编码文件名格式
- 各种路径字符串硬编码
**重构建议**: 提取为常量或配置项
```csharp
public static class LogConstants
{
public const int BatchSize = 500;
public const int FlushIntervalMs = 5000;
}
```
**预估工作量**: 2人天
---
#### 2.6 反射性能开销 (中)
**问题描述**: ServiceBase中频繁使用反射获取属性信息
**示例位置**:
- `ServiceBase.TProperties` - 每次都重新获取
- `ObjectExtension.DicToModel` - 使用反射赋值
**重构建议**:
1. 缓存 PropertyInfo
2. 考虑使用编译表达式替代反射
3. 使用 Source Generator 生成映射代码
**预估工作量**: 3人天
---
#### 2.7 注释缺失 (中)
**问题描述**: 大量方法缺少XML文档注释
**统计**: 约50%的公共方法没有注释
**示例**:
- `RepositoryBase` 中大部分方法缺少注释
- `ServiceBase` 中复杂逻辑缺少注释
- 业务服务层方法缺少注释
**重构建议**: 为所有公共API添加XML文档注释
```csharp
///
/// 通过主键查询数据
///
/// 主键值
/// 查询到的实体,未找到返回null
public TEntity QueryById(object id) { ... }
```
**预估工作量**: 5人天
---
### 三、低优先级问题 (P2 - 长期优化)
#### 3.1 多租户代码被注释 (低)
**问题描述**: RepositoryBase中的多租户架构代码全部被注释
**影响位置**: `RepositoryBase.cs:24-55`
**重构建议**: 要么删除无用代码,要么完成多租户功能
**预估工作量**: 2人天
---
#### 3.2 从库配置代码被注释 (低)
**问题描述**: SqlsugarSetup中的读写分离配置被注释
**影响位置**: `SqlsugarSetup.cs:66-119`
**重构建议**: 删除或启用读写分离功能
**预估工作量**: 1人天
---
#### 3.3 缺少单元测试 (高)
**问题描述**: 项目中完全没有单元测试
**建议**: 添加核心业务逻辑的单元测试
**预估工作量**: 10人天
---
#### 3.4 缺少API文档 (中)
**问题描述**: 只依赖Swagger自动生成,缺少详细的使用文档
**建议**: 编写API使用文档和架构设计文档
**预估工作量**: 5人天
---
#### 3.5 Console.WriteLine在生产代码 (低)
**问题描述**: 多处使用Console.WriteLine
**示例位置**:
- `Logger.cs:64` - 异常时输出到Console
- `BaseDBConfig.cs:52` - SQL错误输出到Console
- `SqlsugarSetup.cs:58-60` - SQL打印
**重构建议**: 使用正式的日志框架
**预估工作量**: 2人天
---
#### 3.6 资源释放不当 (中)
**问题描述**: 部分IDisposable资源未正确释放
**示例**:
- `Logger` 类没有实现IDisposable
- `HttpClientHelper` 的SqlConnection可能未释放
**重构建议**: 实现IDisposable模式
**预估工作量**: 2人天
---
## 重构优先级排序
### 第一阶段: 修复严重问题 (预计10人天)
1. ✅ 修复所有空异常捕获块 (2人天)
2. ✅ 修正命名规范错误 - Creater -> Creator (3人天)
3. ✅ 修复无限循环线程风险 (1人天)
4. ✅ 完成或清理TODO注释 (1人天)
5. ✅ 删除注释掉的多余代码 (2人天)
6. ✅ 使用统一日志框架替代Console (1人天)
### 第二阶段: 改善代码质量 (预计19人天)
7. ✅ 减少代码重复 - Repository异步方法 (5人天)
8. ✅ 拆分过长方法 (4人天)
9. ✅ 统一JSON序列化库 (3人日)
10. ✅ 减少dynamic使用 (2人天)
11. ✅ 提取魔法数字和硬编码 (2人天)
12. ✅ 优化反射性能 (3人天)
### 第三阶段: 完善文档和测试 (预计15人天)
13. ✅ 添加XML文档注释 (5人天)
14. ✅ 添加单元测试 (10人天)
### 第四阶段: 架构优化 (预计10人天)
15. ✅ 实现IDisposable模式 (2人天)
16. ✅ 优化资源管理 (2人天)
17. ✅ 添加性能监控 (2人天)
18. ✅ 优化缓存策略 (2人天)
19. ✅ 编写架构文档 (2人天)
**总预估工作量**: 约54人日 (约10.8人周)
---
## 详细重构建议
### 建议1: 实现统一的异常处理机制
**当前问题**: 异类处理分散,没有统一策略
**解决方案**:
```csharp
// 定义自定义异常基类
public abstract class WmsException : Exception
{
public string ErrorCode { get; }
public WmsException(string code, string message) : base(message)
{
ErrorCode = code;
}
}
// 业务异常
public class BusinessException : WmsException
{
public BusinessException(string code, string message) : base(code, message) { }
}
// 统一异常处理中间件
public class GlobalExceptionHandlerMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
try
{
await next(context);
}
catch (WmsException ex)
{
context.Response.StatusCode = 400;
await context.Response.WriteAsJsonAsync(new {
success = false,
errorCode = ex.ErrorCode,
message = ex.Message
});
}
catch (Exception ex)
{
context.Response.StatusCode = 500;
await context.Response.WriteAsJsonAsync(new {
success = false,
message = "服务器内部错误"
});
}
}
}
```
---
### 建议2: 重构日志系统
**当前问题**: Logger类使用无限循环,类型不安全
**解决方案**:
```csharp
public class WmsLogger : ILogger, IDisposable
{
private readonly Channel _logChannel;
private readonly Task _processingTask;
private readonly CancellationTokenSource _cts;
public WmsLogger()
{
var options = new BoundedChannelOptions(1000)
{
FullMode = BoundedChannelFullMode.Wait
};
_logChannel = Channel.CreateBounded(options);
_cts = new CancellationTokenSource();
_processingTask = Task.Run(() => ProcessLogsAsync(_cts.Token));
}
public async Task LogAsync(LogEntry entry)
{
await _logChannel.Writer.WriteAsync(entry);
}
private async Task ProcessLogsAsync(CancellationToken token)
{
var batch = new List(LogConstants.BatchSize);
while (!token.IsCancellationRequested)
{
try
{
// 收集批量数据
while (batch.Count < LogConstants.BatchSize &&
await _logChannel.Reader.WaitToReadAsync(token))
{
while (_logChannel.Reader.TryRead(out var entry))
{
batch.Add(entry);
}
}
if (batch.Count > 0)
{
await BatchInsertAsync(batch);
batch.Clear();
}
await Task.Delay(LogConstants.FlushIntervalMs, token);
}
catch (OperationCanceledException)
{
break;
}
catch (Exception ex)
{
// 记录到备用位置
System.Diagnostics.Debug.WriteLine($"日志处理失败: {ex.Message}");
}
}
// 处理剩余数据
if (batch.Count > 0)
{
await BatchInsertAsync(batch);
}
}
public void Dispose()
{
_cts.Cancel();
_processingTask.Wait();
_cts.Dispose();
}
}
```
---
### 建议3: 使用编译时反射优化
**当前问题**: 运行时反射性能差
**解决方案**: 使用Source Generator
```csharp
// 定义标记接口
public interface IModelMapper where T : class
{
T MapFrom(Dictionary dict);
}
// Source Generator自动生成实现
// 生成代码示例:
public partial class ModelMapper : IModelMapper
{
public YourEntity MapFrom(Dictionary dict)
{
return new YourEntity
{
Id = dict.TryGetValue("Id", out var id) ? (int)id : 0,
Name = dict.TryGetValue("Name", out var name) ? (string)name : null,
// ... 其他属性
};
}
}
```
---
### 建议4: 实现Repository模式最佳实践
**当前问题**: Repository职责不清晰
**解决方案**:
```csharp
// 定义规范接口
public interface IRepository where T : class
{
Task GetByIdAsync(object id);
Task> GetAllAsync();
Task> FindAsync(Expression> predicate);
Task AddAsync(T entity);
Task AddRangeAsync(IEnumerable entities);
Task UpdateAsync(T entity);
Task DeleteAsync(object id);
Task CountAsync(Expression> predicate = null);
}
// 实现基类
public abstract class RepositoryBase : IRepository where T : class
{
protected readonly ISqlSugarClient Db;
public RepositoryBase(ISqlSugarClient db)
{
Db = db;
}
public virtual async Task GetByIdAsync(object id)
{
return await Db.Queryable().In(id).FirstAsync();
}
// ... 其他实现
}
// 针对特定实体的Repository可以扩展
public interface IUserRepository : IRepository
{
Task GetByUsernameAsync(string username);
}
public class UserRepository : RepositoryBase, IUserRepository
{
public UserRepository(ISqlSugarClient db) : base(db) { }
public async Task GetByUsernameAsync(string username)
{
return await Db.Queryable()
.Where(u => u.Username == username)
.FirstAsync();
}
}
```
---
### 建议5: 实现CQRS模式分离读写
**当前问题**: 所有操作都在Service中混合
**解决方案**:
```csharp
// 命令接口
public interface ICommandHandler
{
Task HandleAsync(TCommand command);
}
// 查询接口
public interface IQueryHandler
{
Task HandleAsync(TQuery query);
}
// 示例命令
public record CreateInboundOrderCommand(
string OrderNo,
int SupplierId,
List Items
) : IRequest;
// 示例查询
public record GetInboundOrderQuery(int OrderId) : IRequest;
// 命令处理器
public class CreateInboundOrderCommandHandler
: ICommandHandler
{
public async Task HandleAsync(CreateInboundOrderCommand command)
{
// 创建逻辑
}
}
```
---
## 重构执行检查清单
### 代码质量检查
- [ ] 所有空catch块已移除或添加日志
- [ ] 所有public方法都有XML注释
- [ ] 没有使用Console.WriteLine的代码
- [ ] 没有魔法数字和硬编码字符串
- [ ] 单个方法不超过50行
- [ ] 单个类不超过500行
- [ ] 圈复杂度控制在10以内
### 架构检查
- [ ] 依赖注入使用构造函数注入
- [ ] 所有IDisposable资源都正确释放
- [ ] 没有循环依赖
- [ ] 接口和实现分离清晰
- [ ] 层次分明,没有越层调用
### 性能检查
- [ ] 数据库查询使用异步方法
- [ ] 反射使用已优化或缓存
- [ ] 集合操作使用LINQ而非循环
- [ ] 字符串操作使用StringBuilder
### 安全检查
- [ ] SQL注入风险已消除
- [ ] 敏感信息已加密存储
- [ ] API有适当的认证和授权
- [ ] 异常信息不暴露内部细节
### 测试检查
- [ ] 核心业务逻辑有单元测试
- [ ] 关键API有集成测试
- [ ] 测试覆盖率不低于60%
---
## 风险评估
### 高风险项
1. **数据模型修改风险**: 修正 `Creater` 为 `Creator` 可能影响现有数据库
- **缓解措施**: 添加数据库列别名映射,分批次迁移
2. **重构ServiceBase风险**: 该类被大量服务继承
- **缓解措施**: 保持公共接口不变,先重构内部实现
### 中风险项
1. **统一JSON库风险**: 可能影响序列化兼容性
- **缓解措施**: 使用JsonConverter保持兼容性
2. **替换日志系统风险**: 日志丢失风险
- **缓解措施**: 新旧系统并行运行一段时间
---
## 建议的重构工具
1. **Roslyn Analyzers**: 自动检测代码问题
2. **SonarQube**: 代码质量分析
3. **Resharper**: 代码重构辅助
4. **Source Generator**: 自动生成代码
5. **xUnit/NUnit**: 单元测试框架
6. **Moq/NSubstitute**: Mock框架
---
## 总结
### 关键发现
1. 项目采用经典分层架构,但实现不够规范
2. 存在严重的代码重复和空异常捕获问题
3. 缺少测试和文档
4. 有一定的技术债务需要清理
### 核心建议
1. **立即修复**: 空异常捕获块、命名错误、无限循环风险
2. **短期改进**: 减少代码重复、统一技术栈、添加注释
3. **长期优化**: 完善测试、优化架构、提升性能
### 预期收益
- 代码可维护性提升 50%
- Bug数量降低 30%
- 新功能开发效率提升 25%
- 系统性能提升 15%
---
**文档生成时间**: 2026-03-10
**分析工具版本**: Claude Code Analysis
**项目版本**: WIDESEA_WMSServer v1.0