视觉上位机、PLC 通信和 Web 看板的积累,这一篇把“全栈架构、登录注册、数据库交互、设备通信”串成一个可落地的视觉系统全栈工程方案

发布时间:2026/10/18 5:11:32
视觉上位机、PLC 通信和 Web 看板的积累,这一篇把“全栈架构、登录注册、数据库交互、设备通信”串成一个可落地的视觉系统全栈工程方案
视觉上位机、PLC 通信和 Web 看板的积累这一篇把“全栈架构、登录注册、数据库交互、设备通信”串成一个可落地的视觉系统全栈工程方案。一、全栈架构四层分离各司其职一套视觉上位机系统如果只写成一个 WinForms 的Form1.cs随着业务增长会迅速失控。正确的做法是严格分层┌─────────────────────────────────────────────────────┐ │ 表示层 (WPF/WinForms) │ │ ├─ 登录/注册界面 ├─ 主操作界面 ├─ 设置界面 │ └───────────────────────┬─────────────────────────────┘ │ 调用 Service ┌───────────────────────▼─────────────────────────────┐ │ 业务逻辑层 (BLL) │ │ ├─ 用户认证服务 ├─ 检测结果管理 │ │ ├─ PLC 通信服务 ├─ 数据上传服务 │ └───────────────────────┬─────────────────────────────┘ │ 调用 Repository / DeviceClient ┌───────────────────────▼─────────────────────────────┐ │ 数据访问层 (DAL) │ 设备通信层 │ │ ├─ EF Core DbContext │ ├─ Snap7 Client │ │ ├─ UserRepository │ ├─ SerialPort 封装 │ │ └─ InspectionRepository │ └─ HttpClient (MES) │ └───────────────────────┬────────┴──────────┬──────────┘ │ │ ┌───────────────────────▼───────────────────▼──────────┐ │ 基础设施 │ │ ├─ SQL Server / SQLite ├─ 西门子 S7-1200/1500 │ │ └─ 日志 (Serilog) └─ MES HTTP API │ └─────────────────────────────────────────────────────┘核心原则表示层不直接碰数据库业务层不直接碰 PLC 字节流。每层只与相邻层通过接口交互。二、数据库交互EF Core 管理用户与检测记录1. 安装与配置使用 EF Core 统一管理 SQL Server 或 SQLite# 安装包dotnetaddpackage Microsoft.EntityFrameworkCore.SqlServer dotnetaddpackage Microsoft.EntityFrameworkCore.Tools// 实体定义publicclassUser{publicintId{get;set;}[Required,MaxLength(50)]publicstringUsername{get;set;}[Required]publicstringPasswordHash{get;set;}[Required]publicstringSalt{get;set;}publicUserRoleRole{get;set;}UserRole.Operator;publicDateTimeCreatedAt{get;set;}DateTime.Now;}publicclassInspectionRecord{publiclongId{get;set;}publicstringSn{get;set;}publicstringStation{get;set;}publicboolIsOk{get;set;}publicdoubleX{get;set;}publicdoubleY{get;set;}publicdoubleAngle{get;set;}publicDateTimeTimestamp{get;set;}DateTime.Now;publicint?UserId{get;set;}// 操作员}// DbContextpublicclassVisionDbContext:DbContext{publicDbSetUserUsers{get;set;}publicDbSetInspectionRecordInspections{get;set;}protectedoverridevoidOnConfiguring(DbContextOptionsBuilderoptions){options.UseSqlServer(Serverlocalhost;DatabaseVisionDB;Trusted_ConnectionTrue;);}}2. 生成数据库Add-MigrationInitialCreateUpdate-Database迁移会自动创建Users和Inspections表无需手写 SQL。三、登录/注册安全是底线1. 密码存储的硬性要求绝不使用 MD5 或 SHA1 直接哈希密码也绝不明文存储。正确做法是使用PBKDF2Rfc2898DeriveBytes每个用户独立随机盐值迭代次数至少 60 万次publicclassPasswordHasher{privateconstintIterations600_000;privateconstintSaltSize16;privateconstintHashSize32;public(stringhash,stringsalt)Hash(stringpassword){byte[]saltRandomNumberGenerator.GetBytes(SaltSize);byte[]hashRfc2898DeriveBytes.Pbkdf2(password,salt,Iterations,HashAlgorithmName.SHA256,HashSize);return(Convert.ToBase64String(hash),Convert.ToBase64String(salt));}publicboolVerify(stringpassword,stringstoredHash,stringstoredSalt){byte[]saltConvert.FromBase64String(storedSalt);byte[]hashConvert.FromBase64String(storedHash);byte[]computedRfc2898DeriveBytes.Pbkdf2(password,salt,Iterations,HashAlgorithmName.SHA256,HashSize);// 恒定时间比较防计时攻击returnCryptographicOperations.FixedTimeEquals(hash,computed);}}FixedTimeEquals是关键——普通的比较会因提前返回而泄露哈希信息。2. 登录与注册服务publicclassAuthService{privatereadonlyVisionDbContext_db;privatereadonlyPasswordHasher_hashernew();publicasyncTaskUserLoginAsync(stringusername,stringpassword){varuserawait_db.Users.FirstOrDefaultAsync(uu.Usernameusername);if(usernull)returnnull;if(!_hasher.Verify(password,user.PasswordHash,user.Salt))returnnull;returnuser;}publicasyncTaskboolRegisterAsync(stringusername,stringpassword){if(await_db.Users.AnyAsync(uu.Usernameusername))returnfalse;var(hash,salt)_hasher.Hash(password);_db.Users.Add(newUser{Usernameusername,PasswordHashhash,Saltsalt});returnawait_db.SaveChangesAsync()0;}}3. WPF 界面调用privateasyncvoidBtnLogin_Click(objectsender,RoutedEventArgse){varuserawait_authService.LoginAsync(TxtUser.Text,TxtPass.Password);if(usernull){MessageBox.Show(用户名或密码错误);return;}// 记录操作员后续检测记录关联CurrentUseruser;newMainWindow().Show();this.Close();}四、上位机与 PLC 通信Snap7 方案1. Snap7 的优势Snap7 是开源的西门子 S7 通信库免费、无需改 PLC 程序、对生产零干扰。一个实际项目用它稳定运行两年、采集逾百万条数据期间对原 PLC 系统零影响。注意S7-1200/1500 的目标 DB 块需取消“优化的块访问”否则无法按绝对地址读写。2. C# 封装usingSnap7;publicclassS7PlcClient:IDisposable{privatereadonlyS7Client_clientnew();privatereadonlystring_ip;publicS7PlcClient(stringip){_ipip;}publicintConnect(){// S7-1200/1500: 机架0槽1return_client.ConnectTo(_ip,0,1);}publicintReadDb(intdbNumber,intstart,intsize,byte[]buffer){return_client.DBRead(dbNumber,start,size,buffer);}publicintWriteDb(intdbNumber,intstart,intsize,byte[]buffer){return_client.DBWrite(dbNumber,start,size,buffer);}publicvoidDispose()_client.Disconnect();}3. 视觉结果写入含握手// DB100 内存布局0.0ResultsValid, 0.1InspectionAck, 2X, 4Y, 6AnglepublicasyncTaskWriteResultAsync(shortx,shorty,shortangle){// 写数据byte[]datanewbyte[6];BitConverter.GetBytes(x).CopyTo(data,0);BitConverter.GetBytes(y).CopyTo(data,2);BitConverter.GetBytes(angle).CopyTo(data,4);_plc.WriteDb(100,2,6,data);// 置握手位byte[]flag{1};_plc.WriteDb(100,0,1,flag);}五、上位机与服务器通信HTTP SignalR视觉系统需要把结果同时“落地”到本地数据库和远程 MES/看板。HTTP 上报 MESPOST JSONpublicclassMesClient{privatereadonlyHttpClient_http;publicMesClient(IHttpClientFactoryfactory){_httpfactory.CreateClient(MesApi);}publicasyncTaskUploadAsync(InspectionRecordrecord){varpayloadnew{record.Sn,record.IsOk,record.Timestamp};usingvarrespawait_http.PostAsJsonAsync(/api/inspection,payload);resp.EnsureSuccessStatusCode();}}SignalR 推送 Web 看板实时更新MES 系统常用 SignalR 将生产状态实时推送到 Web 看板确保看板数据始终最新。视觉上位机在本地写完数据库后也可以通过IHubContext向看板广播await_hub.Clients.All.SendAsync(ReceiveInspection,record);六、完整数据流操作员登录 ↓ WPF 界面 (登录验证 → SQL Server) ↓ 启动检测从 PLC 读取触发信号 (Snap7) ↓ 相机采集 → 算法处理 → 判定 OK/NG ↓ ┌───────────────────┬────────────────────┐ │ 写入本地数据库 │ POST 到 MES │ │ (EF Core) │ (HttpClient) │ └───────────────────┴────────────────────┘ ↓ SignalR 推送到 Web 看板 (实时更新)七、一句话总结全栈视觉系统的核心是分层解耦WPF 只管界面EF Core 只管数据Snap7 只管 PLCHttpClient 只管 MESSignalR 只管推送。每一层独立测试、独立替换系统才可维护、可扩展。