* 创建 AxiOmron.PcbCheck 项目主框架及解决方案 * 添加 Dashboard 和系统设置页面 * 实现 Modbus TCP PLC、扫码枪、SFTP 查询等核心服务 * 集成 Andon 报警、工作流托管服务与日志配置 * 补充项目文档和 UI 设计规范
249 lines
13 KiB
Markdown
249 lines
13 KiB
Markdown
# AGENTS – C# WPF 上位机项目初始化规范
|
||
|
||
本文件为在本仓库中创建和维护 **新的 C# WPF 上位机项目** 的智能体提供统一操作规范,作用域覆盖整个仓库。
|
||
若某个子目录存在更深层级的 `AGENTS.md`,则以更具体的规则为准。
|
||
|
||
## 适用说明
|
||
|
||
- 本仓库中的历史项目、样例项目、参考项目仅用于借鉴工程结构与协作方式,不视为新项目的默认业务实现。
|
||
- 新项目初始化时,优先采用 **.NET 8 + WPF + MVVM Toolkit + Generic Host/DI + NLog** 这一默认技术基线。
|
||
- 不要直接复制参考项目中的业务命名、设备协议、数据库模型、接口定义、配置项或目录命名,除非用户明确要求。
|
||
- 若用户仅要求“初始化项目”或“生成上位机骨架”,默认理解为生成一个结构清晰、可扩展、适合工业桌面应用的 WPF 工程,而不是复制旧项目的业务代码。
|
||
|
||
## 推荐技术基线
|
||
|
||
- 平台:Windows
|
||
- SDK:.NET 8 SDK
|
||
- UI:WPF
|
||
- 项目文件:SDK-style `.csproj`
|
||
- 目标框架:`net8.0-windows`
|
||
- 语言特性:`<Nullable>enable</Nullable>`、`<ImplicitUsings>enable</ImplicitUsings>`
|
||
- MVVM:`CommunityToolkit.Mvvm`
|
||
- 宿主与依赖注入:`Microsoft.Extensions.Hosting`
|
||
- 日志:`NLog` + `NLog.Extensions.Logging`
|
||
- 配置:`appConfig.json` + `appConfig.{Environment}.json`
|
||
- 开发期敏感配置:`UserSecrets` 或环境变量
|
||
- 测试:优先单独测试项目,推荐 xUnit;UI 难测逻辑应下沉到 ViewModel 或 Service
|
||
|
||
## 新项目初始化骨架
|
||
|
||
若无额外约束,推荐使用如下仓库结构:
|
||
|
||
```text
|
||
src/
|
||
<ProjectName>/
|
||
<ProjectName>.csproj
|
||
App.xaml
|
||
App.xaml.cs
|
||
MainWindow.xaml
|
||
MainWindow.xaml.cs
|
||
appConfig.json
|
||
appConfig.Development.json
|
||
NLog.config
|
||
Assets/
|
||
Models/
|
||
ViewModels/
|
||
Views/
|
||
Pages/
|
||
UserControls/
|
||
Services/
|
||
Interfaces/
|
||
Implementations/
|
||
Modules/
|
||
Utils/
|
||
tests/
|
||
<ProjectName>.Tests/
|
||
```
|
||
|
||
约束如下:
|
||
|
||
- `App.xaml` / `App.xaml.cs` 负责应用启动、Host 创建、全局异常处理、配置与日志装配。
|
||
- `MainWindow.xaml` / `.cs` 只负责主窗口装配,不承载核心业务逻辑。
|
||
- `ViewModels/` 保存可绑定状态、命令和页面协调逻辑。
|
||
- `Views/Pages/`、`Views/UserControls/` 保存页面和可复用视图组件。
|
||
- `Services/Interfaces/` 与 `Services/Implementations/` 用于硬件通信、文件处理、MES/PLC/条码/图像处理等业务服务。
|
||
- `Modules/` 用于较独立的能力模块,例如数据库、设备协议封装、审计上传、报表导出等。
|
||
- `Utils/` 仅保留轻量、通用、无业务语义的辅助工具;不要把主要业务逻辑塞入工具类。
|
||
- `tests/` 必须与应用项目分离,避免把测试代码混入正式程序集。
|
||
|
||
若仓库当前只有单个应用项目,也可暂时不建 `src/` 目录,直接在仓库根下放置 `<ProjectName>/`;但若无明确要求,优先采用 `src/ + tests/` 结构。
|
||
|
||
## 项目初始化最低要求
|
||
|
||
新建项目时,至少保证以下内容一次到位:
|
||
|
||
- WPF 应用可以成功还原、编译、启动。
|
||
- `App.xaml.cs` 中建立统一的 Host/DI 启动入口。
|
||
- 主窗口与主要 ViewModel 通过依赖注入创建。
|
||
- 日志系统已接入,且启动阶段异常可落日志。
|
||
- 配置文件支持环境分层加载。
|
||
- 输出目录包含 `appConfig.json`、`appConfig.Development.json`、`NLog.config`。
|
||
- 为未来扩展预留 `Services`、`ViewModels`、`Views`、`Utils`、`Modules` 目录。
|
||
- 若涉及设备通信、轮询、文件监控、批处理等后台任务,必须预先考虑取消、限流、异常记录与 UI 线程切换。
|
||
|
||
## 构建 / 还原 / 运行 / 发布
|
||
|
||
以下命令中的 `<ProjectName>` 代表新建 WPF 项目名:
|
||
|
||
- 创建解决方案:`dotnet new sln -n <SolutionName>`
|
||
- 创建 WPF 项目:`dotnet new wpf -n <ProjectName> --framework net8.0`
|
||
- 还原:`dotnet restore src/<ProjectName>/<ProjectName>.csproj`
|
||
- 调试构建:`dotnet build src/<ProjectName>/<ProjectName>.csproj -c Debug`
|
||
- 发布构建:`dotnet build src/<ProjectName>/<ProjectName>.csproj -c Release`
|
||
- 运行(UI):`dotnet run --project src/<ProjectName>/<ProjectName>.csproj -c Debug`
|
||
- 发布示例:`dotnet publish src/<ProjectName>/<ProjectName>.csproj -c Release -r win-x64 --self-contained false`
|
||
|
||
初始化或修改 `.csproj` 时,至少保持以下属性:
|
||
|
||
- `<UseWPF>true</UseWPF>`
|
||
- `<TargetFramework>net8.0-windows</TargetFramework>`
|
||
- `<Nullable>enable</Nullable>`
|
||
- `<ImplicitUsings>enable</ImplicitUsings>`
|
||
|
||
若项目包含配置、日志、资源或字典文件,需要同步设置 `CopyToOutputDirectory`,确保运行目录完整。
|
||
|
||
## 测试 / 验证
|
||
|
||
- 新项目默认应预留独立测试项目:`tests/<ProjectName>.Tests/`。
|
||
- 优先测试 ViewModel、Service、配置装配、解析逻辑、队列/调度逻辑,不要把核心逻辑压在难以测试的 code-behind 中。
|
||
- 若功能与 UI 强绑定,应先抽离为接口或服务,再进行单元测试或集成测试。
|
||
- 若暂未建立测试项目,至少执行一次构建验证,并手动完成关键 UI 流程检查。
|
||
- 单元测试示例:`dotnet test --filter FullyQualifiedName~命名空间.类名.方法名`
|
||
- 提交前最低要求:`dotnet build` 成功;涉及关键逻辑时应补充对应测试。
|
||
|
||
## Lint / 格式
|
||
|
||
- 若仓库尚未提供统一格式化工具或 `.editorconfig`,保持现有风格一致,不擅自引入新的格式化方案。
|
||
- 保持 using 简洁,移除未使用引用。
|
||
- 使用文件作用域命名空间,除非现有项目明确不采用。
|
||
- 避免只为“看起来更优雅”而大范围重排代码格式。
|
||
|
||
## XML 文档注释规则
|
||
|
||
- 所有 `public` / `internal` / `protected` 类、接口、记录、方法、属性必须有 **中文 XML 文档注释**。
|
||
- 私有成员若逻辑不简单,或方法体超过 10 行,也应补充 XML 注释。
|
||
- 方法注释必须包含:
|
||
- `<summary>`
|
||
- 每个参数的 `<param>`
|
||
- 有返回值时的 `<returns>`
|
||
- 可能抛出异常时的 `<exception>`
|
||
- 异步方法名必须以 `Async` 结尾。
|
||
- 若方法接收 `CancellationToken`,需要在注释中写明取消行为及影响。
|
||
- 涉及命令、绑定、Dispatcher、后台线程、Task.Run、定时器、轮询、文件监控时,注释必须明确线程模型和触发行为。
|
||
- 已有 XML 注释不得删除;修改实现后必须同步更新注释内容。
|
||
|
||
## 代码风格(通用 C#)
|
||
|
||
- 命名空间使用文件作用域写法。
|
||
- 可读性优先:类型不明显时使用显式类型,明显时可使用 `var`。
|
||
- 字段优先使用 `private readonly`,字段命名采用 `_camelCase`。
|
||
- 常量使用 `const PascalCase`。
|
||
- 参数校验只放在系统边界:用户输入、外部接口、文件内容、网络返回、硬件返回等位置。
|
||
- 不要为当前需求之外的场景做预留抽象。
|
||
- 不要新增只被调用一次的帮助类、工具类或接口。
|
||
- 不要为了兼容历史命名而保留无意义的中间层,确认无用即可删除。
|
||
|
||
## MVVM / WPF 实践
|
||
|
||
- 业务逻辑放在 ViewModel 或 Service,code-behind 仅做视图装配、事件桥接、生命周期对接。
|
||
- 命令优先使用 `RelayCommand` / `AsyncRelayCommand`。
|
||
- 可绑定属性优先使用 `[ObservableProperty]` 生成,不手写重复样板代码。
|
||
- 长耗时操作必须使用 `async/await`,不得阻塞 UI 线程。
|
||
- 后台线程不得直接更新绑定到 UI 的对象;涉及 UI 更新时必须切回 Dispatcher。
|
||
- 不要在 View 中直接 `new` 业务服务。
|
||
- 不要在 code-behind 中直接访问数据库、文件系统、MES、PLC、串口、相机或网络接口。
|
||
- 页面切换、对话框协调、状态共享应优先通过 ViewModel 或应用级服务完成。
|
||
- 若项目包含托盘、单实例、后台常驻、自动重连、设备轮询等能力,应将其建模为显式服务并通过 DI 管理生命周期。
|
||
|
||
## 宿主 / DI / 启动约定
|
||
|
||
- 在 `App.xaml.cs` 中集中创建 `HostApplicationBuilder` 或等价 Host 对象。
|
||
- 所有服务、ViewModel、Window、Page 的注册集中管理,不要分散在多个随机文件中。
|
||
- 优先使用构造函数注入,不使用服务定位器模式。
|
||
- 应用启动顺序应清晰:配置加载 → 日志初始化 → Host 构建 → 服务注册 → 主窗口创建与显示。
|
||
- 若涉及全局异常捕获、未观察任务异常、UI 线程异常,应在启动阶段完成统一挂接。
|
||
- 若项目需要单实例约束,应采用明确、可维护的单实例方案,并保证启动顺序可追踪。
|
||
|
||
## 日志 / 异常 / 用户提示
|
||
|
||
- 注入 `ILogger<T>` 进行日志记录,优先使用结构化日志。
|
||
- 记录错误时使用包含异常对象的重载,例如:`_logger.LogError(ex, "消息 {上下文}", value)`。
|
||
- 不要静默吞异常;至少按 Debug / Warning / Error 级别记录。
|
||
- 对用户可感知的失败,要同时提供用户友好提示与详细日志。
|
||
- 对启动失败、配置错误、设备离线、文件访问失败、网络错误等场景,应明确记录上下文。
|
||
- 对于可恢复错误,应在日志中记录恢复动作;对于不可恢复错误,应阻止继续执行并给出清晰提示。
|
||
|
||
## 配置与环境管理
|
||
|
||
- 配置文件默认采用:
|
||
- `appConfig.json`
|
||
- `appConfig.Development.json`
|
||
- 如有必要再增加 `appConfig.Production.json`、`appConfig.Local.json` 等
|
||
- 运行环境通过 `DOTNET_ENVIRONMENT` 或 `ASPNETCORE_ENVIRONMENT` 识别,默认 `Production`。
|
||
- 不要硬编码密钥、口令、连接串、IP、账号。
|
||
- 开发期敏感配置优先使用 `UserSecrets` 或环境变量。
|
||
- 新增配置文件、资源文件、字典文件时,必须同步 `.csproj` 的输出复制规则。
|
||
- 读取配置时优先建立强类型 Options 或清晰的数据模型,不散落魔法字符串。
|
||
|
||
## 集合、并发与 I/O
|
||
|
||
- 文件处理优先使用流式 API,如 `Directory.EnumerateFiles`,避免一次性加载大量文件。
|
||
- 批处理、轮询、文件监控、设备通信等后台任务需具备可取消性。
|
||
- 对共享状态使用明确的并发策略:`SemaphoreSlim`、`ConcurrentQueue`、`ConcurrentDictionary`、Channel 或串行队列。
|
||
- 不要锁住 UI 线程等待后台结果。
|
||
- 对缓冲区、日志列表、待处理队列要设置上限,避免内存无限增长。
|
||
- 所有后台任务都必须定义“谁创建、谁取消、谁记录异常、谁负责收尾”。
|
||
|
||
## 命名约定
|
||
|
||
- 类 / 结构 / 记录 / 枚举:`PascalCase`
|
||
- 接口:`I` 前缀 + `PascalCase`
|
||
- 方法 / 属性 / 事件:`PascalCase`
|
||
- 私有字段:`_camelCase`
|
||
- 局部变量 / 参数:`camelCase`
|
||
- 命令:`*Command`
|
||
- 异步方法:`*Async`
|
||
- 配置类型名应与配置节含义一致,不使用模糊命名如 `ConfigHelper`、`DataManager`、`CommonUtil`
|
||
|
||
## 新项目初始化完成的判定标准
|
||
|
||
一个新建 WPF 上位机项目,至少达到以下状态才可认为“初始化完成”:
|
||
|
||
- 可以成功 `restore`、`build`、`run`
|
||
- 主窗口可以正常显示
|
||
- Host / DI 已接入,主窗口和主 ViewModel 不依赖手工拼装
|
||
- 配置文件可被读取,环境分层生效
|
||
- 日志文件或日志输出可验证
|
||
- 核心目录结构已建立
|
||
- 至少保留一个可扩展的 Service、一个可扩展的 ViewModel、一个基础页面或主窗口示例
|
||
- 若已经接入设备/文件监听/后台任务,则具备最基本的取消与异常记录机制
|
||
|
||
## 贡献检查清单
|
||
|
||
- 是否遵循本文件规定的初始化骨架与技术基线。
|
||
- 是否保持业务逻辑不进入 code-behind。
|
||
- 是否为公开成员补齐中文 XML 注释。
|
||
- 是否已接入 Host/DI、配置和日志。
|
||
- 是否移除未使用 using、无意义抽象和一次性工具层。
|
||
- 是否避免硬编码敏感信息。
|
||
- 是否在涉及后台任务时明确线程切换、取消与异常处理。
|
||
- 是否为新增配置/资源设置输出复制规则。
|
||
- 是否在提交前至少执行一次 `dotnet build`。
|
||
|
||
## 快速命令速查
|
||
|
||
- 新建解决方案:`dotnet new sln -n <SolutionName>`
|
||
- 新建 WPF 项目:`dotnet new wpf -n <ProjectName> --framework net8.0`
|
||
- 添加到解决方案:`dotnet sln add src/<ProjectName>/<ProjectName>.csproj`
|
||
- 还原:`dotnet restore src/<ProjectName>/<ProjectName>.csproj`
|
||
- 调试构建:`dotnet build src/<ProjectName>/<ProjectName>.csproj -c Debug`
|
||
- 发布构建:`dotnet build src/<ProjectName>/<ProjectName>.csproj -c Release`
|
||
- 运行调试:`dotnet run --project src/<ProjectName>/<ProjectName>.csproj -c Debug`
|
||
- 发布示例:`dotnet publish src/<ProjectName>/<ProjectName>.csproj -c Release -r win-x64 --self-contained false`
|
||
- 单测示例:`dotnet test --filter FullyQualifiedName~命名空间.类名.方法名`
|
||
|
||
## 额外说明
|
||
|
||
- 如果后续在某个新项目目录下生成了更具体的 `AGENTS.md`,应把该项目特有的设备协议、数据库约束、部署方式、配置项和 UI 行为写入子级文档,而不是污染仓库级规则。
|
||
- 仓库级 `AGENTS.md` 应保持“可复用、可初始化、不过度绑定具体业务”的定位。
|