* 创建 AxiOmron.PcbCheck 项目主框架及解决方案 * 添加 Dashboard 和系统设置页面 * 实现 Modbus TCP PLC、扫码枪、SFTP 查询等核心服务 * 集成 Andon 报警、工作流托管服务与日志配置 * 补充项目文档和 UI 设计规范
13 KiB
13 KiB
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
新项目初始化骨架
若无额外约束,推荐使用如下仓库结构:
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.jsonappConfig.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应保持“可复用、可初始化、不过度绑定具体业务”的定位。