# 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