0


.net6中, 用数据属性事件触发 用httpclient向服务器提交Mes工单

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;}}}
标签: .net 服务器 运维

本文转载自: https://blog.csdn.net/helldoger/article/details/132517484
版权归原作者 罗迪尼亚的熔岩 所有, 如有侵权,请联系我们删除。

“.net6中, 用数据属性事件触发 用httpclient向服务器提交Mes工单”的评论:

还没有评论