编辑 | blame | 历史 | 原始文档

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.CreaterCreator
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个方法)
- 示例: QureyDataByIdQureyDataByIdAsync 只是调用异步版本

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 - 硬编码文件名格式
- 各种路径字符串硬编码

重构建议: 提取为常量或配置项

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文档注释

/// <summary>
/// 通过主键查询数据
/// </summary>
/// <param name="id">主键值</param>
/// <returns>查询到的实体,未找到返回null</returns>
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人天)

  1. ✅ 减少代码重复 - Repository异步方法 (5人天)
  2. ✅ 拆分过长方法 (4人天)
  3. ✅ 统一JSON序列化库 (3人日)
  4. ✅ 减少dynamic使用 (2人天)
  5. ✅ 提取魔法数字和硬编码 (2人天)
  6. ✅ 优化反射性能 (3人天)

第三阶段: 完善文档和测试 (预计15人天)

  1. ✅ 添加XML文档注释 (5人天)
  2. ✅ 添加单元测试 (10人天)

第四阶段: 架构优化 (预计10人天)

  1. ✅ 实现IDisposable模式 (2人天)
  2. ✅ 优化资源管理 (2人天)
  3. ✅ 添加性能监控 (2人天)
  4. ✅ 优化缓存策略 (2人天)
  5. ✅ 编写架构文档 (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<LogEntry>(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<LogEntry>(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<string, object> dict);
}

// Source Generator自动生成实现
// 生成代码示例:
public partial class ModelMapper : IModelMapper
{
public YourEntity MapFrom(Dictionary<string, object> 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<T?> GetByIdAsync(object id);
Task<IEnumerable> GetAllAsync();
Task<IEnumerable> FindAsync(Expression<Func<T, bool>> predicate);
Task AddAsync(T entity);
Task AddRangeAsync(IEnumerable entities);
Task UpdateAsync(T entity);
Task DeleteAsync(object id);
Task CountAsync(Expression<Func<T, bool>> predicate = null);
}

// 实现基类
public abstract class RepositoryBase : IRepository where T : class
{
protected readonly ISqlSugarClient Db;

public RepositoryBase(ISqlSugarClient db)
{
    Db = db;
}

public virtual async Task<T?> GetByIdAsync(object id)
{
    return await Db.Queryable<T>().In(id).FirstAsync();
}

// ... 其他实现

}

// 针对特定实体的Repository可以扩展
public interface IUserRepository : IRepository
{
Task<User?> GetByUsernameAsync(string username);
}

public class UserRepository : RepositoryBase, IUserRepository
{
public UserRepository(ISqlSugarClient db) : base(db) { }

public async Task<User?> GetByUsernameAsync(string username)
{
    return await Db.Queryable<User>()
        .Where(u => u.Username == username)
        .FirstAsync();
}

}
```


建议5: 实现CQRS模式分离读写

当前问题: 所有操作都在Service中混合

解决方案:
```csharp
// 命令接口
public interface ICommandHandler<TCommand, TResult>
{
Task HandleAsync(TCommand command);
}

// 查询接口
public interface IQueryHandler<TQuery, TResult>
{
Task HandleAsync(TQuery query);
}

// 示例命令
public record CreateInboundOrderCommand(
string OrderNo,
int SupplierId,
List Items
) : IRequest;

// 示例查询
public record GetInboundOrderQuery(int OrderId) : IRequest;

// 命令处理器
public class CreateInboundOrderCommandHandler
: ICommandHandler<CreateInboundOrderCommand, InboundOrder>
{
public async Task HandleAsync(CreateInboundOrderCommand command)
{
// 创建逻辑
}
}
```


重构执行检查清单

代码质量检查

  • [ ] 所有空catch块已移除或添加日志
  • [ ] 所有public方法都有XML注释
  • [ ] 没有使用Console.WriteLine的代码
  • [ ] 没有魔法数字和硬编码字符串
  • [ ] 单个方法不超过50行
  • [ ] 单个类不超过500行
  • [ ] 圈复杂度控制在10以内

架构检查

  • [ ] 依赖注入使用构造函数注入
  • [ ] 所有IDisposable资源都正确释放
  • [ ] 没有循环依赖
  • [ ] 接口和实现分离清晰
  • [ ] 层次分明,没有越层调用

性能检查

  • [ ] 数据库查询使用异步方法
  • [ ] 反射使用已优化或缓存
  • [ ] 集合操作使用LINQ而非循环
  • [ ] 字符串操作使用StringBuilder

安全检查

  • [ ] SQL注入风险已消除
  • [ ] 敏感信息已加密存储
  • [ ] API有适当的认证和授权
  • [ ] 异常信息不暴露内部细节

测试检查

  • [ ] 核心业务逻辑有单元测试
  • [ ] 关键API有集成测试
  • [ ] 测试覆盖率不低于60%

风险评估

高风险项

  1. 数据模型修改风险: 修正 CreaterCreator 可能影响现有数据库
  • 缓解措施: 添加数据库列别名映射,分批次迁移
  1. 重构ServiceBase风险: 该类被大量服务继承
  • 缓解措施: 保持公共接口不变,先重构内部实现

中风险项

  1. 统一JSON库风险: 可能影响序列化兼容性
  • 缓解措施: 使用JsonConverter保持兼容性
  1. 替换日志系统风险: 日志丢失风险
  • 缓解措施: 新旧系统并行运行一段时间

建议的重构工具

  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