news 2026/10/18 5:11:18

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
视觉上位机、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{publicDbSet<User>Users{get;set;}publicDbSet<InspectionRecord>Inspections{get;set;}protectedoverridevoidOnConfiguring(DbContextOptionsBuilderoptions){options.UseSqlServer("Server=localhost;Database=VisionDB;Trusted_Connection=True;");}}

2. 生成数据库

Add-MigrationInitialCreateUpdate-Database

迁移会自动创建Users和Inspections表,无需手写 SQL。

三、登录/注册:安全是底线

1. 密码存储的硬性要求

绝不使用 MD5 或 SHA1 直接哈希密码,也绝不明文存储。正确做法是使用PBKDF2(Rfc2898DeriveBytes),每个用户独立随机盐值,迭代次数至少 60 万次:

publicclassPasswordHasher{privateconstintIterations=600_000;privateconstintSaltSize=16;privateconstintHashSize=32;public(stringhash,stringsalt)Hash(stringpassword){byte[]salt=RandomNumberGenerator.GetBytes(SaltSize);byte[]hash=Rfc2898DeriveBytes.Pbkdf2(password,salt,Iterations,HashAlgorithmName.SHA256,HashSize);return(Convert.ToBase64String(hash),Convert.ToBase64String(salt));}publicboolVerify(stringpassword,stringstoredHash,stringstoredSalt){byte[]salt=Convert.FromBase64String(storedSalt);byte[]hash=Convert.FromBase64String(storedHash);byte[]computed=Rfc2898DeriveBytes.Pbkdf2(password,salt,Iterations,HashAlgorithmName.SHA256,HashSize);// 恒定时间比较,防计时攻击returnCryptographicOperations.FixedTimeEquals(hash,computed);}}

FixedTimeEquals是关键——普通的==比较会因提前返回而泄露哈希信息。

2. 登录与注册服务

publicclassAuthService{privatereadonlyVisionDbContext_db;privatereadonlyPasswordHasher_hasher=new();publicasyncTask<User>LoginAsync(stringusername,stringpassword){varuser=await_db.Users.FirstOrDefaultAsync(u=>u.Username==username);if(user==null)returnnull;if(!_hasher.Verify(password,user.PasswordHash,user.Salt))returnnull;returnuser;}publicasyncTask<bool>RegisterAsync(stringusername,stringpassword){if(await_db.Users.AnyAsync(u=>u.Username==username))returnfalse;var(hash,salt)=_hasher.Hash(password);_db.Users.Add(newUser{Username=username,PasswordHash=hash,Salt=salt});returnawait_db.SaveChangesAsync()>0;}}

3. WPF 界面调用

privateasyncvoidBtnLogin_Click(objectsender,RoutedEventArgse){varuser=await_authService.LoginAsync(TxtUser.Text,TxtPass.Password);if(user==null){MessageBox.Show("用户名或密码错误");return;}// 记录操作员,后续检测记录关联CurrentUser=user;newMainWindow().Show();this.Close();}

四、上位机与 PLC 通信:Snap7 方案

1. Snap7 的优势

Snap7 是开源的西门子 S7 通信库,免费、无需改 PLC 程序、对生产零干扰。一个实际项目用它稳定运行两年、采集逾百万条数据,期间对原 PLC 系统零影响。

注意:S7-1200/1500 的目标 DB 块需取消“优化的块访问”,否则无法按绝对地址读写。

2. C# 封装

usingSnap7;publicclassS7PlcClient:IDisposable{privatereadonlyS7Client_client=new();privatereadonlystring_ip;publicS7PlcClient(stringip){_ip=ip;}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.0=ResultsValid, 0.1=InspectionAck, 2=X, 4=Y, 6=AnglepublicasyncTaskWriteResultAsync(shortx,shorty,shortangle){// 写数据byte[]data=newbyte[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 上报 MES(POST JSON):

publicclassMesClient{privatereadonlyHttpClient_http;publicMesClient(IHttpClientFactoryfactory){_http=factory.CreateClient("MesApi");}publicasyncTaskUploadAsync(InspectionRecordrecord){varpayload=new{record.Sn,record.IsOk,record.Timestamp};usingvarresp=await_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 只管 PLC,HttpClient 只管 MES,SignalR 只管推送。每一层独立测试、独立替换,系统才可维护、可扩展。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 5:10:07

Kafka进阶安装实战:版本选型、集群配置与排错指南

先说个事&#xff1a;上一篇我把Kafka的单机安装流程写得比较细&#xff0c;基本上能把服务拉起来、能收发消息就算通关了。但很多朋友装完单机之后&#xff0c;紧接着就会撞上一连串问题——advertised.listeners写错导致生产者连不上、集群模式复制几份配置忘了改broker.id、…

作者头像 李华
网站建设 2026/10/18 5:09:19

纯静态HTML个人网页模板:大学生期末大作业与课程设计实战指南

简介&#xff1a;这份资源面向正在准备网页设计期末大作业的大学生及HTML初学者&#xff0c;提供多套可直接参考的静态个人网页与个人博客模板&#xff0c;帮助解决作业数量多、无从下手、找不到合适模板等常见困扰。压缩包共收录4261个文件&#xff0c;整体约142.4MB&#xff…

作者头像 李华
网站建设 2026/10/18 5:08:47

Codex桌面端与WorkBuddy CLI组合:本地网关与缓存实现零积分消耗

最近我把 Codex 桌面端和 WorkBuddy CLI 串在一起用了一套组合方案&#xff0c;折腾了一个多星期&#xff0c;终于把调用积分的消耗压到了几乎为零。这套搭配解决的问题很直接&#xff1a;桌面端适合交互式生成、看上下文、即时改代码&#xff1b;CLI 适合批量任务、无人值守、…

作者头像 李华
网站建设 2026/10/18 5:08:46

从 ABAP Cloud 到外部系统,完整理解 Inbound Integration Service 的暴露机制

企业系统真正进入集成阶段以后,经常会碰到这样一类需求,外部系统需要主动调用 SAP,在 SAP 里查询数据、提交业务单据、触发业务动作,或者读取一批用于分析的数据。 这里的方向很关键。 请求不是从 SAP 发出去,而是从外部系统进入 SAP。 在 ABAP Cloud 的术语体系里,这…

作者头像 李华
网站建设 2026/10/18 5:08:21

AI智能体循环工程-第13章第1节-企业级综合项目-项目总览需求PR审查全自动流水线架构设计

第1节 项目总览&#xff1a;需求→PR→审查全自动流水线架构设计 一句话总结&#xff1a;用一张架构图定义最终项目——票据库为脊椎、分诊/修复/审查三个子循环、看板与通知、验证门禁&#xff1b;模块划分与技术选型的全部理由&#xff0c;外加仓库骨架和基建代码的第一行。 …

作者头像 李华
网站建设 2026/10/18 5:08:17

CANN平台Upsample算子迁移实践:语义分割模型性能优化与踩坑指南

在把一套语义分割模型从GPU侧迁到CANN平台的时候&#xff0c;我一开始几乎把所有精力都放在了卷积算子的精度对齐上&#xff0c;结果真正让我头疼的却是一个看似不起眼的算子&#xff1a;Upsample。语义分割模型要求输出和原图同分辨率&#xff0c;backbone又把特征图压得非常小…

作者头像 李华