MES开发中, 客户往往会要求 工单开始时记录工艺数据, 工单结束时将这些工艺数据回传到更上一级的WES系统中. 因为MES系统和PLC 是多线程读取, 所以加锁, 事件触发是常用手段.
usingMyWebApiTest.PLC;usingMyWebApiTest.Service;usingMyWebApiTest.Service.Entry;usingMyWebApiTest.Service.Entry.Imp;usingMyWebApiTest.Service.Factory;usingMyWebApiTest.Service.Factory.Impl;usingMyWebApiTest.Utils;usingSerilog;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();
usingS7.Net;namespaceMyWebApiTest.Service.Entry{publicinterfaceIS7ConnService{voidConnPlc();bool MyIsConnected
{get;}Plc MyS7Master {get;}}}
usingMyWebApiTest.PLC;usingMyWebApiTest.Service.Entry;usingS7.Net;namespaceMyWebApiTest.Service.Entry.Imp{publicclassS7ConnServiceImpl:IS7ConnService{publicS7ConnServiceImpl(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;}privatereadonlyIConfiguration configuration;privatereadonlyHttpClient httpClient;privatereadonlyILogger<S7ConnServiceImpl> logger;privateMyS7Entry myS7Entry;privatestring myIp;privatePlc myS7Master =null;privateMyS7EntityRecive? myS7test =newMyS7EntityRecive();privateMyS7Entry myS7Data =newMyS7Entry();privatebool myIsConnected =false;privateCancellationTokenSource cts =new();privateint errorTimes =0;privatestaticreadonlyobject lockObj =newobject();// 创建一个对象作为锁publicPlc MyS7Master
{get=> myS7Master;}publicMyS7Entry MyS7Data
{get=> myS7Data;set=> myS7Data =value;}publicbool MyIsConnected
{get=> myIsConnected;set{if(myIsConnected ==false&&value==true){
logger.LogInformation("PLC连接成功!");}
myIsConnected =value;}}publicvoidConnPlc(){
Task.Run(async()=>{while(!cts.IsCancellationRequested){if(myS7Master ==null||!MyIsConnected){try{
myS7Master =newPlc(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);}}elseif(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,并且在修改属性时使用,
不会导致循环依赖锁,因此不会发生死锁。
但要注意,死锁可能在其他情况下发生,比如在涉及多个锁的复杂情况下,
或者在锁嵌套的情况下。确保你的代码中不会出现多个锁之间的循环依赖,
以及在锁内部避免阻塞线程,以保证代码的正常执行。
*/
usingSystem.ComponentModel;namespaceMyWebApiTest.PLC{publicclassMyS7Entry:INotifyPropertyChanged{publiceventPropertyChangedEventHandler? PropertyChanged;privateshort myShort1;publicshort MyShort1
{get=> myShort1;set{if(myShort1 !=value){if(myShort1 ==1&&value==0){OnPropertyChanged(nameof(MyShort1));}
myShort1 =value;}}}privateshort myShort2;publicshort MyShort2
{get=> myShort2;set{if(myShort2 !=value){if(myShort2 ==1&&value==0){OnPropertyChanged(nameof(MyShort2));}
myShort2 =value;}}}privatevoidOnPropertyChanged(string propertyName){
PropertyChanged?.Invoke(this,newPropertyChangedEventArgs(propertyName));}}}
namespaceMyWebApiTest.PLC{publicclassMyS7EntityRecive{publicshort MyShort1 {get;set;}publicshort MyShort2 {get;set;}}}
usingMyWebApiTest.entities;usingMyWebApiTest.PLC;usingMyWebApiTest.Service.Entry;usingSystem.Text.Json;namespaceMyWebApiTest.Utils{publicclassStartupInitializationService:IHostedService{privatereadonlyMyS7Entry myS7Entry;privatereadonlyIS7ConnService s7ConnService;privatereadonlyILogger<StartupInitializationService> logger;privatereadonlyHttpClient httpClient;publicStartupInitializationService(MyS7Entry myS7Entry
,IS7ConnService s7ConnService
,ILogger<StartupInitializationService> logger
,HttpClient httpClient
){this.myS7Entry = myS7Entry;this.s7ConnService = s7ConnService;this.logger = logger;this.httpClient = httpClient;}publicTaskStartAsync(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 =newStringContent(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.");}}elseif(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 =newStringContent(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;}publicTaskStopAsync(CancellationToken cancellationToken){// 在应用程序停止时执行清理逻辑(如果有必要)return Task.CompletedTask;}}}
本文转载自: https://blog.csdn.net/helldoger/article/details/132517484
版权归原作者 罗迪尼亚的熔岩 所有, 如有侵权,请联系我们删除。
版权归原作者 罗迪尼亚的熔岩 所有, 如有侵权,请联系我们删除。