# StandardScene 代码审查报告 > 审查对象:`E:\Work\Core\Simple-FR\StandardSence`(StandardScene.Core / StandardScene.Devices / StandardScene.Protocol.VDA5050) > 审查方式:全量反模式扫描(ripgrep)+ 关键文件精读 + 编译告警分类(dotnet build --no-incremental) > 目标框架:`net8.0-windows`(最终目标 `net8.0`) > 报告日期:2026-06-09 --- ## 一、审查范围与方法 - **代码规模**:113 个 `.cs` 文件;最大文件 `WebApi.cs`(2661 行)、`AbstractLoopMission.cs`(1858 行)。 - **扫描维度**:并发/线程、异常处理、报文解析边界、资源管理、配置硬编码、日志、UI/业务耦合、安全、编译告警。 - **证据标注**: - `精读确认`:已逐行读取、行号精确。 - `扫描命中`:ripgrep 命中文件级,行号待整改时逐一核对。 --- ## 二、总体评价与子系统评分 | 子系统 | 评分 | 说明 | |---|---|---| | 设备驱动(StandardScene.Devices·新) | ★★★★☆ | `ModbusDoorController` 工程化优秀,可作团队样板 | | TCP 基础设施(AsyncTcpClient) | ★★★★☆ | 锁/陈旧回调防护/重连完善,少量瑕疵 | | Coders(重构后) | ★★★★☆ | 本轮已去重,结构清晰 | | CarTypes 车型族 | ★★☆☆☆ | 巨类、async void、空 catch、硬编码集中 | | 任务族 Missions | ★★☆☆☆ | Thread.Abort、while(true)+Sleep、状态机分散 | | 充电 Charge | ★★☆☆☆ | 实时报文路径越界风险、UDP 线程模型粗放 | | VDA5050 协议 | ★★☆☆☆ | 硬编码 IP、async void、throw ex、Console 日志 | | WebApi(老 Nancy) | ★☆☆☆☆ | 2661 行上帝文件、无鉴权反射调用、模板代码爆炸 | | Commons / 公共层 | ★★☆☆☆ | 上帝工具类、重复实现、隐性 bug | **核心判断**:技术债**集中在旧模块**(CarTypes / Missions / Charge / VDA5050 / WebApi / Commons);**新写模块**(Devices、AsyncTcpClient)质量明显更高,说明团队具备写好代码的能力,债务主要是历史遗留。整改应"以新模块为范本、按子系统收敛旧债"。 --- ## 三、问题严重级别汇总 | 级别 | 含义 | 主要条目 | |---|---|---| | **P0 阻断** | .NET8 下会崩溃/失效,或存在安全风险 | Thread.Abort 被吞、WebApi 无鉴权反射、实时报文越界 | | **P1 高危** | 生产环境易触发故障/难排障 | 硬编码 IP、async void+throw、空 catch、HttpClient 滥用 | | **P2 结构** | 可维护性/扩展性差 | 上帝类、重复代码、Console 日志、UI/业务耦合 | | **P3 整洁** | 编译告警与代码卫生 | 45 项告警(重复 using、未用字段、隐藏成员等) | --- ## 四、P0 阻断级问题 ### P0-1 `Thread.Abort()` 在 .NET8 必抛异常且被静默吞掉(线程停不掉) `Thread.Abort()` 在 .NET8 抛 `PlatformNotSupportedException`(告警 SYSLIB0006,共 14 条/双配置)。多处 `Abort()` 外层是空 `catch{}`,导致**异常被吞、线程实际未停止**——任务"停止"后后台线程仍在跑,造成重复下发、资源泄漏、状态错乱。 精读确认命中点: | 文件 | 行 | |---|---| | `StandardScene.Core/Chained/AbstractLoopMission.cs` | 1314 `_strategyThread?.Abort()`、1329 `_logicThread?.Abort()` | | `StandardScene.Core/Charge/StandardChargeMission.cs` | 681 `myThread?.Abort()`、684 `ChargeThread?.Abort()` | | `StandardScene.Core/Scheduler/SecuritySignalMission.cs` | 176 `myThread?.Abort()` | | `StandardScene.Core/Scheduler/NodeIsEnableMission.cs` | 121 `myThread?.Abort()` | | `StandardScene.Core/Scheduler/HeartBeatMission.cs` | 68 `_myThread?.Abort()` | | `StandardScene.Core/Chained/AbstractChainedDeliveryMission.cs` | 1606 `myThread.Abort()` | 典型代码(`AbstractLoopMission.cs:1309`,`精读确认`): ```1309:1334:E:\Work\Core\Simple-FR\StandardSence\StandardScene.Core\Chained\AbstractLoopMission.cs public virtual void StopLoop() { try { _strategyRunning = false; _strategyThread?.Abort(); _strategyThread = null; ... } catch { } } ``` **修复方向**:改为**协作式停止**——已有 `_strategyRunning/_logicRunning` 布尔标志,循环体应周期检查该标志退出;线程创建用 `IsBackground=true`,停止时 `flag=false` 后 `Join(timeout)`。删除所有 `Abort()`。对阻塞型循环用 `CancellationToken` + 可中断等待(`Task.Delay(token)` / `ManualResetEventSlim.Wait(token)`)替代 `Thread.Sleep`。参考 `ModbusDoorController` 的 `CancellationTokenSource` 范式。 --- ### P0-2 WebApi 反射接口:无鉴权远程调用任意方法(RCE 级风险) `StandardScene.Core/WebApi.cs`(`精读确认`,272–314 / 332–368)暴露: ```272:296:E:\Work\Core\Simple-FR\StandardSence\StandardScene.Core\WebApi.cs Get("/car_reflection/execute/{id}/{method}", parameters => { ... methodInfo = car.GetType().GetMethod((string)parameters.method); ... return ExecuteMethod(methodInfo, car, queryParams); }); ``` `mission_reflection/execute/{id}/{method}` 同款。问题:**通过 HTTP 即可按名反射调用 Car/Mission 上任意 public 方法**,无身份校验、无方法白名单、无危险方法拦截。结合 `GET` 语义,配置不当会暴露在内网甚至外网,构成命令执行级攻击面。 **修复方向**: 1. 最小化:加访问令牌/来源 IP 限制(中间件统一校验)。 2. 方法白名单:仅允许标注了 `[MethodMember]`(或新增 `[WebInvokable]`)的方法被反射调用;拒绝其余。 3. 语义化:执行类操作改 `POST`;统一错误响应封装(见 P2-2)。 --- ### P0-3 实时报文解析按固定下标取值、缺长度校验(IndexOutOfRange 崩溃) 对比发现两条解析路径**风险等级不同**: - ✅ **正确范本**:`StandardScene.Core/Charge/CommunicationMessageService.cs`(`精读确认`)在取下标前先校验 `parts.Length < 30 / < 10`(198、276 行),再访问 `bytes[28]` 等,越界已被防住。 - ❌ **风险路径**:实时 UDP/回调路径按固定下标直接取值,未见等价长度校验(`扫描命中`): - `StandardScene.Core/ChargeUdpService.cs`(`message[28]` 等) - `StandardScene.Devices/Charge/PCBChargeStation.cs`(`OnUdpMessage` 中 `message[1]`) - `StandardScene.Core/ChargeStationType/MuXingChargeStation.cs` 设备掉线/半包/异常帧时,直接 `IndexOutOfRangeException`,且若发生在 UDP 接收线程会拖垮整条接收链路。 **修复方向**:所有报文解析入口统一"先校验长度(与帧头/类型匹配)再取值",越界返回 null 并 `Diagnosis.Log` 记录原始帧;抽出 `ChargeFrameParser` 复用 `CommunicationMessageService` 的安全解析。 --- ## 五、P1 高危问题 ### P1-1 配置硬编码(IP/URL/路径),多 AGV/换环境必失效(`扫描命中` 14 文件) 最典型(`精读确认`)`StandardScene.Protocol.VDA5050/VDACar/VDA5050Car.cs:150`: ```150:168:E:\Work\Core\Simple-FR\StandardSence\StandardScene.Protocol.VDA5050\VDACar\VDA5050Car.cs public async void GetVDA5050StateFromC() { try { //string jsonResponse1 = await hc.GetStringAsync($"http://{this.address}:8008/getStat"); string jsonResponse1 = await hc.GetStringAsync($"http://192.168.2.1:8008/getStat"); ... } catch (Exception ex) { } } ``` 把按车 `this.address` 的写法**注释掉、写死 `192.168.2.1`**——多 AGV 场景必然全部打到同一地址;外加空 catch 吞错,故障"静默"。其余命中:`Kiva.cs`/`Forklift.cs`(`192.168.2.1:8008`)、`Map.cs`(`127.0.0.1:4321`)、`LoopMission.cs`(西门子 PLC IP)、`TransportDeliveryCallbacks.cs`(回调 URL)、`StandardCADTool.cs`(Windows 盘符路径)等。 **修复方向**:抽 `scene.json`/配置中心统一注入;禁止业务代码内联端点;`StandardCADTool` 路径改相对/可配置。 ### P1-2 `async void` + 在其中 `throw`(CA2200 失栈)→ 进程级崩溃风险 - `Kiva.cs:619` `public new async void ForceStop()`(`精读确认`):`async void`,catch 内 `MessageBox.Show`(UI 耦合),最外层 `Console.WriteLine(e); throw;`——`async void` 抛出的异常无法被调用方捕获,直接打到 `SynchronizationContext`/线程池,可致进程崩溃。`new` 还隐藏基类 `ForceStop`(CS0114)。 - `VDA5050Car.cs:240` `throw ex;`(`精读确认`)破坏原始堆栈(CA2200,全仓 4 条)。`DummyCar.cs` 同款。 - `async void` 在 CarTypes/Charge/VDA5050/CAD 等多文件广泛存在(`扫描命中`)。 **修复方向**:事件处理器之外一律 `async Task`;确需 `async void` 的入口用 `try/catch` 兜底并 `Diagnosis.Log`,不得外抛;`throw ex;` → `throw;`。 ### P1-3 空 `catch{}` 静默吞异常(`扫描命中` 10 文件) `Kiva.cs`、`VDA5050Car.cs`、`FLChargeStation.cs`、`AbstractLoopMission.cs`、`Commons.cs`、`AsyncTcpClient.cs`、`LoopViewer.cs` 等。`Kiva.cs:606`、`VDA5050Car.cs:165` 为典型业务路径空 catch。 > 注:`AsyncTcpClient` / `ModbusDoorController` 中环绕 `Close()/Dispose()` 的空 catch 属可接受的清理兜底,应保留但加注释;业务路径空 catch 必须改为记录日志。 ### P1-4 同步阻塞调用 `.Result/.Wait()/GetAwaiter().GetResult()`(`扫描命中` 7 文件) `ButtonMission.cs`、`DoorMission.cs`、`VDA5050Car.cs` 等。`Kiva.cs:635 status.programs.task.Wait()`(`精读确认`)在 UI/线程上下文易死锁。**修复**:异步链路打通,避免 sync-over-async。 ### P1-5 `new HttpClient()` 反复实例化(Socket 耗尽)(`扫描命中`) `Forklift.cs`/`Kiva.cs`/`VDA5050Car.cs`/`WebApi.cs` 等频繁 `new HttpClient`。**修复**:单例或 `IHttpClientFactory`/`SocketsHttpHandler`(设 `PooledConnectionLifetime`)。 --- ## 六、P2 结构 / 质量问题 ### P2-1 `Commons.cs` 上帝工具类(`精读确认`) - `AddOrUpdateCarField/SiteField/MissionField` "ContainsKey→Remove+Add / else Add" 模板**重复 4 份**,应为 `dict[key]=value`。 - `AddOrUpdateTag` 名为 update 实为 add(更新逻辑被注释),重复键会抛错,命名误导。 - `CarValue`:存在 `electricCurrent` 时**忽略入参 key** 直接返回,疑似 bug。 - `GoSite` catch 内 `Console.WriteLine + Thread.Sleep(3000)`,注释写"重新执行"但**并未真正重试**。 - 调度 `NearestTask`(约 398–538)巨函数、深嵌套、大段 `#region ObsoleteCode` 注释代码、魔法优先级 `Priority=50`。 ### P2-2 `WebApi.cs` 2661 行上帝文件(`精读确认`) 错误响应 `new { Success=false, Code=500, Data="null", Message=... }` 模板**复制几十处**;路由全堆一个文件。**修复**:抽 `ApiResult.Fail/Ok` 帮助器;按资源拆分路由模块;老接口归入 `WebApi.Core(deprecated)` 并规划迁移。 ### P2-3 日志体系不统一(`扫描命中` 22 文件 `Console.WriteLine`) 与 `Diagnosis.Log` 混用。`ModbusDoorController` 已全程 `Diagnosis.Log`,应作为统一范式推广;禁用 `Console.WriteLine` 于业务代码。 ### P2-4 UI 与业务耦合(`扫描命中`) `MessageBox.Show` 出现在 `Commons.cs`(TrafficControl.OnDeadLock)、`Kiva.cs:648`、`DoorManager.cs`、`ButtonBoxManager.cs` 等业务/管理类中。**修复**:业务层只发事件/日志,弹窗交由 UI 层(后续 migu 平台)。 ### P2-5 `while(true)+Thread.Sleep` 忙等/阻塞(`扫描命中` 13 文件) `Forklift.cs`、`StandardChargeMission.cs`、`ChargeUdpService.cs`、`VDA5050Car.cs` 等。**修复**:改 `CancellationToken`+可中断等待或定时器;与 P0-1 协作式停止一并处理。 ### P2-6 AsyncTcpClient 细节(`精读确认`) - `Send` 失败抛 `InvalidProgramException`(异常类型不当,应 `InvalidOperationException`/自定义)。 - `HandleDatagramWritten` 调 `EndWrite` 无 try,写失败异常落到线程池无人观测。 - `uint on = 1;` 未使用字段(CS0414)。 --- ## 七、编译告警分类(全量,双配置合计 90 实例 ≈ 45/配置) | 告警码 | 数量 | 含义 | 处置 | |---|---|---|---| | CS0108 | 16 | 隐藏继承成员未加 `new` | 显式 `new`/`override` 或改名 | | CS4014 | 14 | 调用未 `await`(即发即弃) | 显式 `await` 或 `_ =` 并说明 | | CS0414 | 14 | 私有字段赋值但从未使用 | 删除 | | SYSLIB0006 | 14 | `Thread.Abort` 已弃用 | 见 **P0-1** | | CS0105 | 6 | 重复 using | 删除 | | CS0162 | 6 | 不可达代码 | 清理 | | CS0168 | 6 | 变量声明未用 | 删除 | | CA2200 | 4 | `throw ex` 失栈 | 改 `throw;` | | CS8321 | 2 | 局部函数未用 | 删除(如 VDA5050Car `monitor()`) | | CS0169 | 2 | 字段从未使用 | 删除 | | CS0114 | 2 | 隐藏继承成员(如 ForceStop) | `override`/`new` | | CS0219 | 2 | 变量赋值未用 | 删除 | | CS0649 | 2 | 字段从未赋值 | 初始化或删除 | --- ## 八、分子系统评述(摘要,详版见架构方案) - **CarTypes**:`BasicCarFields/SiteFields/TrackFields/PlanFields` 字段袋设计合理(`BasicFields.cs`,`CarLength/CarWidth` 默认 `-1` 作"未配置"哨兵,已被避障 Coder 正确利用);但具体车型(Kiva/Forklift/VDA5050Car)是巨类,混杂通信、状态、UI、调度,async void/空 catch/硬编码集中。 - **Coders**:本轮已完成磁导航统一与避障去重(`AvoidanceParamCoder` 4 参 + `AvoidanceParamLWCoder` 2 参),结构清晰,建议继续把车型内联 Coder 收敛到 `CommonTrackCoders`。 - **Missions**:Chained/InterLock/Scheduler 线程模型粗放(裸 `new Thread`+`Abort`+`while(true)`),状态机散落字符串 `status.status`。建议统一 `MissionRunnerBase`(CancellationToken + 状态枚举)。 - **Charge**:解析存在"安全范本"与"风险路径"并存(见 P0-3);UDP 服务与 Mission 线程耦合。 - **Devices(新)**:`ModbusDoorController` 优秀;唯一瑕疵是用析构函数兜底 `Disconnect`(在 GC 线程取锁+`Wait`,有风险),应实现 `IDisposable` 显式释放。 - **VDA5050**:MQTT/HTTP 异步用法不规范(async void、throw ex、硬编码 IP、Console 日志),状态处理 `ProcessCacheAndSendOrderMessage` 内大量 Console。 - **WebApi**:见 P0-2 / P2-2,最高优先级重构对象。 --- ## 九、正面样板(建议作为团队基线) 1. `StandardScene.Devices/Door/ModbusDoorController.cs`:`CancellationTokenSource` 协作式停止、`lock` 线程安全、变更检测(`_lastSentControl`)、重连节流、统一 `Diagnosis.Log`、资源清理。 2. `StandardScene.Core/TCP/AsyncTcpClient.cs`:锁保护、陈旧回调防护、自动重连。 3. `StandardScene.Core/Charge/CommunicationMessageService.cs`:报文解析前置长度校验(安全解析范本)。 --- ## 十、整改路线图 **第 1 批(P0,本次执行)** 1. Thread.Abort → 协作式停止(6 文件 8 处)。 2. WebApi 反射 execute 加来源校验 + `[MethodMember]` 白名单。 3. 充电实时报文路径补长度校验(复用安全解析)。 **第 2 批(P1)** 4. 硬编码端点配置化(VDA5050/Kiva/Forklift/Map/Loop/CAD)。 5. `async void`→`Task`、`throw ex`→`throw`、业务空 catch 加日志。 6. HttpClient 单例化;sync-over-async 拆解。 **第 3 批(P2/结构)** 7. `ApiResult` 帮助器 + WebApi 拆分;`Commons` 拆服务、修 `CarValue`/`GoSite`/`AddOrUpdate`。 8. 统一 `Diagnosis.Log`;UI 解耦;`MissionRunnerBase` 统一线程/状态机。 **第 4 批(P3 卫生)** 9. 清 45 项告警(重复 using、未用字段、不可达代码、隐藏成员)。 --- ## 附录:扫描方法 - 反模式:`rg` 扫描 `Thread.Abort` / `catch\s*\{\s*\}` / `throw ex;` / `async void` / `\.Result|\.Wait\(\)` / 硬编码 IP / `Console.WriteLine` / `while\s*\(\s*true\s*\)` / `new HttpClient` / `MessageBox.Show` / 魔法下标。 - 告警:`dotnet build --no-incremental` → `_buildwarnings.txt` → 按告警码聚合计数。 - 精读:AsyncTcpClient、Commons、CommunicationMessageService、VDA5050Car、WebApi、Kiva、AbstractLoopMission、ModbusDoorController、BasicFields 等。