.net6中, 用数据属性事件触发 用httpclient向服务器提交Mes工单
MES开发中, 客户往往会要求 工单开始时记录工艺数据, 工单结束时将这些工艺数据回传到更上一级的WES系统中. 因为MES系统和PLC 是多线程读取, 所以加锁, 事件触发是常用手段.
using MyWebApiTest.PLC;
using MyWebApiTest.Service;
using MyWebApiTest.Service.Entry;
using MyWebApiTest.Service.Entry.Imp;
using MyWebApiTest.Service.Factory;
using MyWebApiTest.Service.Factory.Impl;
using MyWebApiTest.Utils;
using Serilog;var builder = WebApplication.CreateBuilder(args);// Add services to the container.//日志
builder.Host.UseSerilog((context, logger) =>
{logger.ReadFrom.Configuration(context.Configuration);logger.Enrich.FromLogContext();
});// Add services to the container.
builder.Configuration.AddJsonFile("appsettings.json", false, true);
var cfg = builder.Configuration;
builder.Services.AddSingleton<IConfiguration>(cfg);//ORM
builder.Services.AddSingleton<ISqlSugarService ,SqlSugarServiceImpl>();
builder.Services.AddSingleton<SqlSugarHelper>();builder.Services.AddSingleton<IAbsFactoryService, AbsFactoryServiceImpl>();builder.Services.AddSingleton<IConnFactoryService, ConnFactoryServiceImpl2>();
builder.Services.AddSingleton<IConnFactoryService, ConnFactoryServiceImpl1>();//PLC数据
builder.Services.AddSingleton<MyS7Entry>();
builder.Services.AddSingleton<IS7ConnService, S7ConnServiceImpl>();//运行初始化任务 测试client
//builder.Services.AddSingleton<IHostedService, StartupInitializationService>();//client
builder.Services.AddHttpClient();//AutoMapper
builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());builder.Services.AddControllers();
builder.Services.AddCors(c => c.AddPolicy("any", p => p.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin()));
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();//日志
builder.Host.UseSerilog((context, logger) =>
{logger.ReadFrom.Configuration(context.Configuration);logger.Enrich.FromLogContext();
});var app = builder.Build();// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{app.UseSwagger();app.UseSwaggerUI();
}
app.UseCors("any");app.UseAuthorization();app.MapControllers();app.Run();
using S7.Net;namespace MyWebApiTest.Service.Entry
{public interface IS7ConnService{void ConnPlc();bool MyIsConnected{get;}Plc MyS7Master { get; }}
}
using MyWebApiTest.PLC;
using MyWebApiTest.Service.Entry;
using S7.Net;namespace MyWebApiTest.Service.Entry.Imp
{public class S7ConnServiceImpl : IS7ConnService{public S7ConnServiceImpl(IConfiguration configuration,HttpClient httpClient,ILogger<S7ConnServiceImpl> logger,MyS7Entry myS7Entry){this.configuration = configuration;this.httpClient = httpClient;this.logger = logger;this.myS7Entry = myS7Entry;myIp = configuration.GetSection("PlcIp").Value;}private readonly IConfiguration configuration;private readonly HttpClient httpClient;private readonly ILogger<S7ConnServiceImpl> logger;private MyS7Entry myS7Entry;private string myIp;private Plc myS7Master = null;private MyS7EntityRecive? myS7test = new MyS7EntityRecive();private MyS7Entry myS7Data = new MyS7Entry();private bool myIsConnected = false;private CancellationTokenSource cts = new();private int errorTimes = 0;private static readonly object lockObj = new object(); // 创建一个对象作为锁public Plc MyS7Master{get => myS7Master;}public MyS7Entry MyS7Data{get => myS7Data;set => myS7Data = value;}public bool MyIsConnected{get => myIsConnected;set{if (myIsConnected == false && value == true){logger.LogInformation("PLC连接成功!");}myIsConnected = value;}}public void ConnPlc(){Task.Run(async () =>{while (!cts.IsCancellationRequested){if (myS7Master == null || !MyIsConnected){try{myS7Master = new Plc(CpuType.S71500, myIp, 0, 0);myS7Master.Open();MyIsConnected = myS7Master.IsConnected;}catch (Exception ex){myS7Master?.Close();myS7Master = null;MyIsConnected = false;logger.LogError(ex.Message);await Task.Delay(2000);}}else if (MyIsConnected){//注入Client//var url = "http://localhost:5190/api/private/v1/My/MyGet"; // 目标 Web API 的地址//var response = await httpClient.GetAsync(url);//if (response.IsSuccessStatusCode)//{// var content = await response.Content.ReadAsStringAsync();// logger.LogError(content);//}try{MyIsConnected = myS7Master.IsConnected;await Task.Delay(1000);myS7test = await myS7Master.ReadClassAsync<MyS7EntityRecive>(31, 416);lock (lockObj){myS7Entry.MyShort1 = myS7test.MyShort1;myS7Entry.MyShort2 = myS7test.MyShort2;}logger.LogInformation(myS7Entry.MyShort1.ToString() + "====");}catch (Exception ex){errorTimes++;await Task.Delay(1000);logger.LogError($"读取时发生错误:{ex.Message}");logger.LogError($"读取时发生错误次数:{errorTimes}");myS7Master.Close();MyIsConnected = false;myS7Master = null;}}}}, cts.Token);}}
}/*使用了 lock 来保护 myS7Entry.MyShort1 和 myS7Entry.MyShort2 的同时修改,
以确保在同一时间只有一个线程可以修改这两个属性。这是一种常见的使用锁的方式,
目的是避免竞态条件和数据不一致性。死锁通常发生在两个或多个线程之间存在循环依赖锁的情况下,
导致它们互相等待对方释放锁。在你的代码中,只有一个 lock,并且在修改属性时使用,
不会导致循环依赖锁,因此不会发生死锁。但要注意,死锁可能在其他情况下发生,比如在涉及多个锁的复杂情况下,
或者在锁嵌套的情况下。确保你的代码中不会出现多个锁之间的循环依赖,
以及在锁内部避免阻塞线程,以保证代码的正常执行。*/
using System.ComponentModel;namespace MyWebApiTest.PLC
{public class MyS7Entry : INotifyPropertyChanged{public event PropertyChangedEventHandler? PropertyChanged;private short myShort1;public short MyShort1{get => myShort1;set{if (myShort1 != value){if (myShort1 == 1 && value == 0){OnPropertyChanged(nameof(MyShort1));}myShort1 = value;}}}private short myShort2;public short MyShort2{get => myShort2;set{if (myShort2 != value){if (myShort2 == 1 && value == 0){OnPropertyChanged(nameof(MyShort2));}myShort2 = value;}}}private void OnPropertyChanged(string propertyName){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}}
}
namespace MyWebApiTest.PLC
{public class MyS7EntityRecive{public short MyShort1 { get; set; }public short MyShort2 { get; set; }}
}
using MyWebApiTest.entities;
using MyWebApiTest.PLC;
using MyWebApiTest.Service.Entry;
using System.Text.Json;namespace MyWebApiTest.Utils
{public class StartupInitializationService : IHostedService{private readonly MyS7Entry myS7Entry;private readonly IS7ConnService s7ConnService;private readonly ILogger<StartupInitializationService> logger;private readonly HttpClient httpClient;public StartupInitializationService(MyS7Entry myS7Entry, IS7ConnService s7ConnService, ILogger<StartupInitializationService> logger, HttpClient httpClient){this.myS7Entry = myS7Entry;this.s7ConnService = s7ConnService;this.logger = logger;this.httpClient = httpClient;}public Task StartAsync(CancellationToken cancellationToken){try{s7ConnService.ConnPlc();}catch (Exception ex){logger.LogError($"网络错误:{ex.Message}");return Task.CompletedTask;}logger.LogWarning("初始化函数成功");myS7Entry.PropertyChanged += async (s, e) =>{if (e.PropertyName == "MyShort1"){string? url = "http://127.0.0.1:8081/endpoint/mes/kx/reportA";Student stu = new(){Id = 1,Name = "MyBool1",Age = 999};var json = JsonSerializer.Serialize(stu);var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");var response = await httpClient.PostAsync(url, content);if (response.IsSuccessStatusCode){logger.LogInformation("Data sent successfullyS1.");}else{logger.LogInformation("Failed to send dataS1.");}}else if (e.PropertyName == "MyShort2"){string? url = "http://127.0.0.1:8081/endpoint/mes/kx/reportB";Student stu = new(){Id = 2,Name = "MyBool2",Age = 888};var json = JsonSerializer.Serialize(stu);var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");var response = await httpClient.PostAsync(url, content);if (response.IsSuccessStatusCode){logger.LogInformation("Data sent successfullyS1.");}else{logger.LogInformation("Failed to send dataS1.");}}};return Task.CompletedTask;}public Task StopAsync(CancellationToken cancellationToken){// 在应用程序停止时执行清理逻辑(如果有必要)return Task.CompletedTask;}}
}
相关文章:
.net6中, 用数据属性事件触发 用httpclient向服务器提交Mes工单
MES开发中, 客户往往会要求 工单开始时记录工艺数据, 工单结束时将这些工艺数据回传到更上一级的WES系统中. 因为MES系统和PLC 是多线程读取, 所以加锁, 事件触发是常用手段. using MyWebApiTest.PLC; using MyWebApiTest.Service; using MyWebApiTest.Service.Entry; using M…...
sin(A)的意义
若存在矩阵A,则sin(A)表示对于矩阵A的每一个元素,进行对应的函数运算。 如:...
ctfshow-web14
0x00 前言 CTF 加解密合集CTF Web合集 0x01 题目 0x02 Write Up 首先看到这个,swith,那么直接输入4,则会打印$url的值 然后访问一下 查看一下,发现完整的请求是http://c7ff9ed6-dccd-4d01-907a-f1c61c016c15.challenge.ctf.sho…...
数据结构—循环队列(环形队列)
循环队列(环形队列) 循环队列的概念及结构循环队列的实现 循环队列的概念及结构 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。…...
vue3 实现按钮权限管理
在做后台管理系统时,经常会有权限管理的功能,这里来记录一下关于按钮权限管理的实现方法 1、自定义指令 v-permission。新建js文件用来写指令代码。 export default function btnPerms(app) {app.directive(permission, {mounted(el, binding) {if (!p…...
C语言练习4(巩固提升)
C语言练习4 选择题 前言 面对复杂变化的世界,人类社会向何处去?亚洲前途在哪里?我认为,回答这些时代之问,我们要不畏浮云遮望眼,善于拨云见日,把握历史规律,认清世界大势。 选择题 …...
将AI融入CG特效工作流;对谈Dify创始人张路宇;关于Llama 2的一切资源;普林斯顿LLM高阶课程;LLM当前的10大挑战 | ShowMeAI日报
👀日报&周刊合集 | 🎡生产力工具与行业应用大全 | 🧡 点赞关注评论拜托啦! 🤖 将AI融入CG特效工作流,体验极致的效率提升 BV1pP411r7HY 这是 B站UP主 特效小哥studio 和 拓星研究所 联合投稿的一个AI特…...
Vue2学习笔记のVue中的ajax
目录 Vue中的ajaxvue脚手架配置代理方法一方法二 插槽 hello, 这篇文章是Vue2学习笔记的第四篇,也是第四章:Vue中的ajax。 Vue中的ajax vue脚手架配置代理 方法一 在vue.config.js中添加如下配置: devServer:{proxy:"http://localho…...
C# 使用NPOI操作EXCEL
1.添加NOPI 引用->管理NuGet程序包->添加NOPI 2.相关程序集 3....
分布式 - 服务器Nginx:一小时入门系列之 return 指令
文章目录 1. return 指令语法2. return code URL 示例3. return code text 示例4. return URL 示例 1. return 指令语法 return指令用于立即停止当前请求的处理,并返回指定的HTTP状态码和响应头信息,它可以用于在Nginx中生成自定义错误页面,…...
【Linux】ext4和xfs扩大,缩小lv后,无法识别如何操作
虚拟机系统异常,挂载到其他环境如何修复系统盘 1、环境 UOS 1060E x86环境 模拟异常环境: 1060e系统,使用lvm缩小磁盘后,出现异常,将异常磁盘挂载到其他服务器中,但存在问题发现有uuid相同的问题。 为…...
基于HarmonyOS ArkUI实现音乐列表功能
本节将演示如何在基于HarmonyOS ArkUI的List组件来实现音乐列表功能。 本文涉及的所有源码,均可以在文末链接中找到。 活动主页 华为开发者论坛 规则要求具体要求如下: 第1步:观看<HarmonyOS第一课>“营”在暑期•系列直播&#x…...
Android系统启动流程 源码解析
Android系统启动流程 本文链接:https://blog.csdn.net/feather_wch/article/details/132518105 有道云脑图:https://note.youdao.com/s/GZ9d8vzO 1、整体流程 Boot RoomBootLoaderidle kthreadinit init ServiceManagerzygote zygote SystemServerap…...
【头歌】构建哈夫曼树及编码
构建哈夫曼树及编码 第1关:构建哈夫曼树 任务描述 本关任务:构建哈夫曼树,从键盘读入字符个数n及这n个字符出现的频率即权值,构造带权路径最短的最优二叉树(哈夫曼树)。 相关知识 哈夫曼树的定义 设二叉树具有n个带权值的叶子结点{w1,w2,...,wn},从根结点到每个叶…...
创建本地镜像
通过前面文章的阅读,读者已经了解到所谓的容器实际上是在父镜像的基础上创建了一个可读写的文件层级,所有的修改操作都在这个文件层级上进行,而父镜像并未受影响,如果读者需要根据这种修改创建一个新的本地镜像,有两种…...
网络编程套接字(2): 简单的UDP网络程序
文章目录 网络编程套接字(2): 简单的UDP网络程序3. 简单的UDP网络程序3.1 服务端创建(1) 创建套接字(2) 绑定端口号(3) sockaddr_in结构体(4) 数据的接收与发送接收发送 3.2 客户端创建3.3 代码编写(1) v1_简单发送消息(2) v2_小写转大写(3) v3_模拟命令行解释器(4) v4_多线程版…...
Android Mvvm设计模式的详解与实战教程
一、介绍 在开发设计模式中,模式经历了多次迭代,从MVC到MVP,再到如今的MVVM。发现的过程其实很简单,就是为了项目更好的管理。 设计模式严格来说属于软件工程的范畴,但是如今在各大面试中或者开发中,设计模…...
软考A计划-系统集成项目管理工程师-小抄手册(共25章节)-下
点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 👉关于作者 专注于Android/Unity和各种游…...
渗透测试是什么?怎么做?
渗透测试报告 一、什么是渗透测试? 渗透测试是可以帮助用户对目前自己的网络、系统、应用的缺陷有相对直观的认识和了解。渗透测试尽可能地以黑客视角对用户网络安全性进行检查,对目标网络、系统和应用的安全性作深入的探测,发现系统最脆弱的…...
【软件安装】Python安装详细教程(附安装包)
软件简介 Python由荷兰数学和计算机科学研究学会的Guido van Rossum 于1990 年代初设计,作为一门叫做ABC语言的替代品。Python提供了高效的高级数据结构,还能简单有效地面向对象编程。Python语法和动态类型,以及解释型语言的本质,…...
微信小程序的form表单提交
获取input有两种方法: 第一:bindsubmit方法 注意: 1.使用form里面定义bindsubmit事件 2.bindsubmit事件需要配合button里面定义的formType“submit” 操作 3.设置input的name值来获取对应的数据 <form bindsubmit"formSubmit"…...
WOFOST模型与PCSE模型应用
实现作物产量的准确估算对于农田生态系统响应全球变化、可持续发展、科学粮食政策制定、粮食安全维护都至关重要。传统的经验模型、光能利用率模型等估产模型原理简单,数据容易获取,但是作物生长发育非常复杂,中间涉及众多生理生化过程&#…...
5-W806-RC522-SPI
main.c #include <stdio.h> #include "wm_hal.h" #include "rc522.h"int main(void) {SystemClock_Config(CPU_CLK_160M);printf("enter main\r\n");HAL_Init();RC522_Init();PcdReset();M500PcdConfigISOType ( A );//设置工作方式IC_te…...
Python实现自动登录+获取数据
前言 Dy这个东西想必大家都用过,而且还经常刷,今天就来用代码,获取它的视频数据 环境使用 Python 3.8 Pycharm 模块使用 requests selenium json re 一. 数据来源分析 1. 明确需求 明确采集网站以及数据内容 网址: https://www.dy.co…...
yolov8热力图可视化
安装pytorch_grad_cam pip install grad-cam自动化生成不同层的bash脚本 # 循环10次,将i的值从0到9 for i in $(seq 0 13) doecho "Running iteration $i";python yolov8_heatmap.py $i; done热力图生成python代码 import warnings warnings.filterwarn…...
【SpringBoot】第一篇:redis使用
背景: 本文是教初学者如何正确使用和接入redis。 一、引入依赖 <!--redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><depen…...
Springboot profile多环境配置
1. 前言 profile用于多环境的激活和配置,用来切换生产,测试,本地等多套不通环境的配置。如果每次去更改配置就非常麻烦,profile就是用来切换多环境配置的。 2. 配置方法 三种方式。 2.1 多profile文件方式 在resource目录下新…...
(1)进程与线程区别
1.什么是线程、进程 进程:操作系统资源分配的基本单位线程:处理器任务调度和执行的基本单位。 一个进程至少有一个线程,线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。 2.并行与并发 一个基本的事实前提&#x…...
学习JAVA打卡第四十天
对象的字符串表示 在此类中我们讲过,所有的类都默认是java.lang包中object类的子类或间接子类。 Object类有一个public String toString()方法,一个对象通过调用该方法可以获得该对象的字符串表示。一个对象调用toString法(&…...
【跟小嘉学 Rust 编程】十四、关于 Cargo 和 Crates.io
系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…...
合肥做百度网站/建立网站平台需要多少钱
1.内存保护单元MPU与Cortex - M3的相同,MPU是一个Cortex - M4中用于内存保护的可选组件。处理器支持标准ARMv7内存保护系统结构模型。您可以使用在MPU执行 特权/访问 规则,或者独立的进程。这个MPU提供全面支持: 保护区 重叠保护区域…...
建设银行网站会员基本信息/网盘搜索神器
本系列博客旨在帮助大家理解java垃圾收集器及其工作原理,这是系列的第二篇。java垃圾回收事实上是由一个能够进行自己主动内存管理的进程完毕的,这使得程序猿在写代码的时候不必过多考虑内存释放与回收的问题。垃圾收集器怎样初始化:作为一个…...
揭阳建设局网站/网站建设定制
微课程 | 第十三课《全局序列视频演示》上一期我们介绍了全局序列的原理,接下来我们通过视频来演示一下全局序列功能。我们来看一下这两种全局序列是怎么工作的。 时间戳算法 首先是 snowflake ,也就是所谓时间戳算法。 微课程 | 第十三课《全局序列视频…...
日本不良网站正能量大豆/河南seo推广
图虫网-写在前面 经历了一顿噼里啪啦的操作之后,终于我把博客写到了第10篇,后面,慢慢的会涉及到更多的爬虫模块,有人问scrapy 啥时候开始用,这个我预计要在30篇以后了吧,后面的套路依旧慢节奏的࿰…...
wordpress文章页随机文章/网络营销推广的基本手段
PDF文件设置了打开密码,但是文件如果不经常使用,还有可能会忘记正确密码或者记住的密码输入的时候显示错误。但是文件内容很重要一定要打开文件,这种时候,我们只能找回正确的打开密码才能够解决问题。 【PDF解密大师】密码找回_破…...
阿拉伯文网站怎么做/个人在线网站推广
IT系统应用于企业管理:架构模式,领域分析,项目管理。非常好的一本书,第一次读完一遍后想立即再读一遍的书。同类的书中也是最好的那类。第一章,大型网站架构演化初始阶段的网站架构应用服务和数据服务分离使用缓存改善…...