完成S7变量启用和停用更新

This commit is contained in:
2025-09-16 14:42:23 +08:00
parent 3102938f92
commit 74fde6bd8b
59 changed files with 226 additions and 454 deletions

View File

@@ -1,18 +1,13 @@
using System.Collections.Concurrent;
using DMS.Application.Events;
using DMS.Application.Interfaces;
using DMS.Core.Interfaces.Services;
using DMS.Core.Models;
using DMS.Infrastructure.Interfaces.Services;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using DMS.Application.DTOs.Events;
using DMS.Core.Models;
using DMS.Application.Interfaces;
using DMS.Core.Interfaces.Services;
namespace DMS.Infrastructure.Services
namespace DMS.Infrastructure.Services.Mqtt
{
/// <summary>
/// MQTT后台服务负责管理MQTT连接和数据传输

View File

@@ -1,10 +1,8 @@
using System.Collections.Concurrent;
using DMS.Core.Models;
using DMS.Infrastructure.Interfaces.Services;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace DMS.Infrastructure.Services
namespace DMS.Infrastructure.Services.Mqtt
{
/// <summary>
/// MQTT设备上下文用于存储单个MQTT服务器的连接信息和状态

View File

@@ -5,11 +5,8 @@ using MQTTnet.Client;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Options;
using MQTTnet.Client.Receiving;
using System;
using System.Threading.Tasks;
namespace DMS.Infrastructure.Services
namespace DMS.Infrastructure.Services.Mqtt
{
/// <summary>
/// MQTT服务实现类用于与MQTT服务器进行通信

View File

@@ -1,8 +1,7 @@
using DMS.Infrastructure.Interfaces.Services;
using Microsoft.Extensions.Logging;
using System;
namespace DMS.Infrastructure.Services
namespace DMS.Infrastructure.Services.Mqtt
{
/// <summary>
/// MQTT服务工厂实现类用于创建MQTT服务实例

View File

@@ -1,18 +1,13 @@
using DMS.Infrastructure.Interfaces.Services;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DMS.Core.Models;
using DMS.Application.Interfaces;
using DMS.Core.Interfaces.Services;
using DMS.Core.Models;
using DMS.Infrastructure.Interfaces.Services;
using Microsoft.Extensions.Logging;
namespace DMS.Infrastructure.Services
namespace DMS.Infrastructure.Services.Mqtt
{
/// <summary>
/// MQTT服务管理器负责管理MQTT连接和变量监控

View File

@@ -4,12 +4,8 @@ using DMS.Infrastructure.Models;
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DMS.Infrastructure.Services
namespace DMS.Infrastructure.Services.OpcUa
{
public class OpcUaService : IOpcUaService
{

View File

@@ -1,10 +1,10 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using DMS.Application.DTOs;
using DMS.Application.Events;
using DMS.Application.Interfaces;
using DMS.Application.Models;
using DMS.Core.Enums;
using DMS.Core.Events;
using DMS.Infrastructure.Configuration;
using DMS.Infrastructure.Interfaces.Services;
using DMS.Infrastructure.Models;
@@ -12,7 +12,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using VariableValueChangedEventArgs = DMS.Core.Events.VariableValueChangedEventArgs;
namespace DMS.Infrastructure.Services
namespace DMS.Infrastructure.Services.OpcUa
{
/// <summary>
/// OPC UA服务管理器负责管理OPC UA连接、订阅和变量监控

View File

@@ -1,12 +1,12 @@
using DMS.Application.DTOs;
using DMS.Application.DTOs.Events;
using DMS.Application.Events;
using DMS.Application.Interfaces;
using DMS.Core.Enums;
using DMS.Infrastructure.Interfaces.Services;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace DMS.Infrastructure.Services
namespace DMS.Infrastructure.Services.OpcUa
{
/// <summary>
/// 优化后的OPC UA后台服务

View File

@@ -1,21 +1,17 @@
using System.Collections.Concurrent;
using DMS.Application.DTOs;
using DMS.Application.DTOs.Events;
using DMS.Application.Interfaces;
using DMS.Core.Enums;
using DMS.Core.Models;
using Microsoft.Extensions.Hosting;
using S7.Net;
using S7.Net.Types;
using DateTime = System.DateTime;
using Microsoft.Extensions.Logging;
using DMS.Core.Interfaces;
using DMS.Infrastructure.Interfaces.Services;
using System.Diagnostics;
using System.Globalization;
using DMS.Application.DTOs;
using DMS.Application.Events;
using DMS.Application.Interfaces;
using DMS.Application.Models;
using DMS.Core.Enums;
using DMS.Core.Events;
using DMS.Infrastructure.Interfaces.Services;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using DateTime = System.DateTime;
namespace DMS.Infrastructure.Services;
namespace DMS.Infrastructure.Services.S7;
/// <summary>
/// 优化的S7后台服务继承自BackgroundService用于在后台高效地轮询S7 PLC设备数据。
@@ -24,6 +20,7 @@ public class OptimizedS7BackgroundService : BackgroundService
{
private readonly IAppDataCenterService _appDataCenterService;
private readonly IAppDataStorageService _appDataStorageService;
private readonly IEventService _eventService;
private readonly IDataProcessingService _dataProcessingService;
private readonly IS7ServiceManager _s7ServiceManager;
private readonly ILogger<OptimizedS7BackgroundService> _logger;
@@ -42,18 +39,22 @@ public class OptimizedS7BackgroundService : BackgroundService
public OptimizedS7BackgroundService(
IAppDataCenterService appDataCenterService,
IAppDataStorageService appDataStorageService,
IEventService eventService,
IDataProcessingService dataProcessingService,
IS7ServiceManager s7ServiceManager,
ILogger<OptimizedS7BackgroundService> logger)
{
_appDataCenterService = appDataCenterService;
_appDataStorageService = appDataStorageService;
_eventService = eventService;
_dataProcessingService = dataProcessingService;
_s7ServiceManager = s7ServiceManager;
_logger = logger;
_appDataCenterService.DataLoaderService.OnLoadDataCompleted += OnLoadDataCompleted;
}
private void OnLoadDataCompleted(object? sender, DataLoadCompletedEventArgs e)
{
@@ -245,10 +246,10 @@ public class OptimizedS7BackgroundService : BackgroundService
// 将更新后的数据推入处理队列。
await _dataProcessingService.EnqueueAsync(new VariableContext(variable, value));
}
else
{
_logger.LogWarning($"未能从设备 {device.Name} 读取变量 {variable.S7Address} 的值");
}
// else
// {
// _logger.LogWarning($"未能从设备 {device.Name} 读取变量 {variable.S7Address} 的值");
// }
}
}
catch (Exception ex)

View File

@@ -1,19 +1,14 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using DMS.Application.DTOs;
using DMS.Application.Models;
using DMS.Core.Enums;
using DMS.Core.Models;
using DMS.Infrastructure.Interfaces;
using DMS.Infrastructure.Interfaces.Services;
using Microsoft.Extensions.Logging;
using S7.Net;
using S7.Net.Types;
using CpuType = DMS.Core.Enums.CpuType;
using DateTime = System.DateTime;
namespace DMS.Infrastructure.Services
namespace DMS.Infrastructure.Services.S7
{
/// <summary>
/// S7设备代理类专门负责与单个S7 PLC进行所有通信
@@ -57,16 +52,16 @@ namespace DMS.Infrastructure.Services
}
}
private S7.Net.CpuType ConvertCpuType(CpuType cpuType)
private global::S7.Net.CpuType ConvertCpuType(CpuType cpuType)
{
return cpuType switch
{
CpuType.S7200 => S7.Net.CpuType.S7200,
CpuType.S7300 => S7.Net.CpuType.S7300,
CpuType.S7400 => S7.Net.CpuType.S7400,
CpuType.S71200 => S7.Net.CpuType.S71200,
CpuType.S71500 => S7.Net.CpuType.S71500,
_ => S7.Net.CpuType.S71200
CpuType.S7200 => global::S7.Net.CpuType.S7200,
CpuType.S7300 => global::S7.Net.CpuType.S7300,
CpuType.S7400 => global::S7.Net.CpuType.S7400,
CpuType.S71200 => global::S7.Net.CpuType.S71200,
CpuType.S71500 => global::S7.Net.CpuType.S71500,
_ => global::S7.Net.CpuType.S71200
};
}

View File

@@ -1,10 +1,9 @@
using DMS.Infrastructure.Interfaces.Services;
using Microsoft.Extensions.Logging;
using NLog;
using S7.Net;
using S7.Net.Types;
namespace DMS.Infrastructure.Services
namespace DMS.Infrastructure.Services.S7
{
/// <summary>
/// S7服务实现类用于与S7 PLC进行通信

View File

@@ -1,7 +1,7 @@
using DMS.Infrastructure.Interfaces.Services;
using Microsoft.Extensions.Logging;
namespace DMS.Infrastructure.Services
namespace DMS.Infrastructure.Services.S7
{
/// <summary>
/// S7服务工厂实现用于创建S7Service实例

View File

@@ -1,18 +1,14 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using DMS.Application.DTOs;
using DMS.Application.Events;
using DMS.Application.Interfaces;
using DMS.Core.Enums;
using DMS.Core.Events;
using DMS.Infrastructure.Interfaces.Services;
using Microsoft.Extensions.Logging;
using NPOI.HSSF.Record;
namespace DMS.Infrastructure.Services
namespace DMS.Infrastructure.Services.S7
{
/// <summary>
/// S7服务管理器负责管理S7连接和变量监控
@@ -23,6 +19,7 @@ namespace DMS.Infrastructure.Services
private readonly IEventService _eventService;
private readonly IDataProcessingService _dataProcessingService;
private readonly IAppDataCenterService _appDataCenterService;
private readonly IAppDataStorageService _appDataStorageService;
private readonly IS7ServiceFactory _s7ServiceFactory;
private readonly ConcurrentDictionary<int, S7DeviceContext> _deviceContexts;
private readonly SemaphoreSlim _semaphore;
@@ -33,15 +30,44 @@ namespace DMS.Infrastructure.Services
IEventService eventService,
IDataProcessingService dataProcessingService,
IAppDataCenterService appDataCenterService,
IAppDataStorageService appDataStorageService,
IS7ServiceFactory s7ServiceFactory)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_eventService = eventService;
_dataProcessingService = dataProcessingService ?? throw new ArgumentNullException(nameof(dataProcessingService));
_appDataCenterService = appDataCenterService ?? throw new ArgumentNullException(nameof(appDataCenterService));
_dataProcessingService
= dataProcessingService ?? throw new ArgumentNullException(nameof(dataProcessingService));
_appDataCenterService
= appDataCenterService ?? throw new ArgumentNullException(nameof(appDataCenterService));
_appDataStorageService = appDataStorageService;
_s7ServiceFactory = s7ServiceFactory ?? throw new ArgumentNullException(nameof(s7ServiceFactory));
_deviceContexts = new ConcurrentDictionary<int, S7DeviceContext>();
_semaphore = new SemaphoreSlim(10, 10); // 默认最大并发连接数为10
_eventService.OnVariableActiveChanged += OnVariableActiveChanged;
}
private void OnVariableActiveChanged(object? sender, VariablesActiveChangedEventArgs e)
{
if (_deviceContexts.TryGetValue(e.DeviceId, out var s7DeviceContext))
{
var variables = _appDataStorageService.Variables.Values.Where(v => e.VariableIds.Contains(v.Id))
.ToList();
foreach (var variable in variables)
{
if (e.NewStatus)
{
// 变量启用,从轮询列表中添加变量
s7DeviceContext.Variables.AddOrUpdate(variable.S7Address,variable, (key, oldValue) => variable);
}
else
{
// 变量停用,从轮询列表中移除变量
s7DeviceContext.Variables.Remove(variable.S7Address, out _);
}
}
}
}
/// <summary>
@@ -69,12 +95,12 @@ namespace DMS.Infrastructure.Services
}
var context = new S7DeviceContext
{
Device = device,
S7Service = _s7ServiceFactory.CreateService(),
Variables = new ConcurrentDictionary<string, VariableDto>(),
IsConnected = false
};
{
Device = device,
S7Service = _s7ServiceFactory.CreateService(),
Variables = new ConcurrentDictionary<string, VariableDto>(),
IsConnected = false
};
_deviceContexts.AddOrUpdate(device.Id, context, (key, oldValue) => context);
_logger.LogInformation("已添加设备 {DeviceId} 到监控列表", device.Id);
@@ -104,6 +130,7 @@ namespace DMS.Infrastructure.Services
{
context.Variables.AddOrUpdate(variable.S7Address, variable, (key, oldValue) => variable);
}
_logger.LogInformation("已更新设备 {DeviceId} 的变量列表,共 {Count} 个变量", deviceId, variables.Count);
}
}
@@ -135,6 +162,7 @@ namespace DMS.Infrastructure.Services
{
return _deviceContexts.Keys.ToList();
}
/// <summary>
/// 获取所有监控的设备ID
/// </summary>
@@ -155,13 +183,14 @@ namespace DMS.Infrastructure.Services
try
{
_logger.LogInformation("正在连接设备 {DeviceName} ({IpAddress}:{Port})",
context.Device.Name, context.Device.IpAddress, context.Device.Port);
context.Device.Name, context.Device.IpAddress, context.Device.Port);
var stopwatch = Stopwatch.StartNew();
// 设置连接超时
using var timeoutToken = new CancellationTokenSource(5000); // 5秒超时
using var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token);
using var linkedToken
= CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token);
var cpuType = ConvertCpuType(context.Device.CpuType);
await context.S7Service.ConnectAsync(
@@ -173,13 +202,13 @@ namespace DMS.Infrastructure.Services
stopwatch.Stop();
_logger.LogInformation("设备 {DeviceName} 连接耗时 {ElapsedMs} ms",
context.Device.Name, stopwatch.ElapsedMilliseconds);
context.Device.Name, stopwatch.ElapsedMilliseconds);
if (context.S7Service.IsConnected)
{
context.IsConnected = true;
_logger.LogInformation("设备 {DeviceName} 连接成功", context.Device.Name);
}
else
@@ -190,15 +219,14 @@ namespace DMS.Infrastructure.Services
catch (Exception ex)
{
_logger.LogError(ex, "连接设备 {DeviceName} 时发生错误: {ErrorMessage}",
context.Device.Name, ex.Message);
context.Device.Name, ex.Message);
context.IsConnected = false;
}
finally
{
_eventService.RaiseDeviceConnectChanged(
this, new DeviceConnectChangedEventArgs(context.Device.Id, context.Device.Name, context.IsConnected));
this,
new DeviceConnectChangedEventArgs(context.Device.Id, context.Device.Name, context.IsConnected));
_semaphore.Release();
}
}
@@ -216,32 +244,33 @@ namespace DMS.Infrastructure.Services
_logger.LogInformation("正在断开设备 {DeviceName} 的连接", context.Device.Name);
await context.S7Service.DisconnectAsync();
context.IsConnected = false;
_eventService.RaiseDeviceConnectChanged(
this, new DeviceConnectChangedEventArgs(context.Device.Id, context.Device.Name, context.IsConnected));
this,
new DeviceConnectChangedEventArgs(context.Device.Id, context.Device.Name, context.IsConnected));
_logger.LogInformation("设备 {DeviceName} 连接已断开", context.Device.Name);
}
catch (Exception ex)
{
_logger.LogError(ex, "断开设备 {DeviceName} 连接时发生错误: {ErrorMessage}",
context.Device.Name, ex.Message);
context.Device.Name, ex.Message);
}
}
/// <summary>
/// 将字符串形式的CPU类型转换为S7.Net.CpuType枚举
/// </summary>
private S7.Net.CpuType ConvertCpuType(CpuType cpuType)
private global::S7.Net.CpuType ConvertCpuType(CpuType cpuType)
{
return cpuType switch
{
CpuType.S7200 => S7.Net.CpuType.S7200,
CpuType.S7300 => S7.Net.CpuType.S7300,
CpuType.S7400 => S7.Net.CpuType.S7400,
CpuType.S71200 => S7.Net.CpuType.S71200,
CpuType.S71500 => S7.Net.CpuType.S71500,
_ => S7.Net.CpuType.S71200 // 默认值
};
{
CpuType.S7200 => global::S7.Net.CpuType.S7200,
CpuType.S7300 => global::S7.Net.CpuType.S7300,
CpuType.S7400 => global::S7.Net.CpuType.S7400,
CpuType.S71200 => global::S7.Net.CpuType.S71200,
CpuType.S71500 => global::S7.Net.CpuType.S71500,
_ => global::S7.Net.CpuType.S71200 // 默认值
};
}
/// <summary>
@@ -287,7 +316,8 @@ namespace DMS.Infrastructure.Services
/// <summary>
/// 批量断开设备连接
/// </summary>
public async Task DisconnectDevicesAsync(IEnumerable<int> deviceIds, CancellationToken cancellationToken = default)
public async Task DisconnectDevicesAsync(IEnumerable<int> deviceIds,
CancellationToken cancellationToken = default)
{
var disconnectTasks = new List<Task>();
@@ -319,7 +349,8 @@ namespace DMS.Infrastructure.Services
// 断开所有设备连接
var deviceIds = _deviceContexts.Keys.ToList();
DisconnectDevicesAsync(deviceIds).Wait(TimeSpan.FromSeconds(10));
DisconnectDevicesAsync(deviceIds)
.Wait(TimeSpan.FromSeconds(10));
// 释放其他资源
_semaphore?.Dispose();

View File

@@ -1,241 +0,0 @@
using System.Collections.Concurrent;
using DMS.Application.DTOs;
using DMS.Application.DTOs.Events;
using DMS.Application.Interfaces;
using DMS.Core.Enums;
using DMS.Core.Models;
using Microsoft.Extensions.Hosting;
using S7.Net;
using S7.Net.Types;
using DateTime = System.DateTime;
using Microsoft.Extensions.Logging;
using DMS.Core.Interfaces;
using DMS.Infrastructure.Interfaces;
using DMS.Infrastructure.Interfaces.Services;
namespace DMS.Infrastructure.Services;
/// <summary>
/// S7后台服务继承自BackgroundService采用"编排者-代理"模式管理所有S7设备。
/// S7BackgroundService作为编排者负责创建、管理和销毁每个设备专属的S7DeviceAgent。
/// 每个S7DeviceAgent作为代理专门负责与一个S7 PLC进行所有交互。
/// </summary>
public class S7BackgroundService : BackgroundService
{
private readonly IAppDataCenterService _appDataCenterService;
private readonly IAppDataStorageService _appDataStorageService;
private readonly IDataProcessingService _dataProcessingService;
private readonly IChannelBus _channelBus;
private readonly IMessenger _messenger;
private readonly ILogger<S7BackgroundService> _logger;
private readonly SemaphoreSlim _reloadSemaphore = new SemaphoreSlim(0);
// 存储活动的S7设备代理键为设备ID值为代理实例
private readonly ConcurrentDictionary<int, S7DeviceAgent> _activeAgents = new();
// S7轮询一遍后的等待时间
private readonly int _s7PollOnceSleepTimeMs = 100;
/// <summary>
/// 构造函数,注入所需的服务
/// </summary>
public S7BackgroundService(
IAppDataCenterService appDataCenterService,
IAppDataStorageService appDataStorageService,
IDataProcessingService dataProcessingService,
IChannelBus channelBus,
IMessenger messenger,
ILogger<S7BackgroundService> logger)
{
_appDataCenterService = appDataCenterService;
_appDataStorageService = appDataStorageService;
_dataProcessingService = dataProcessingService;
_channelBus = channelBus;
_messenger = messenger;
_logger = logger;
_appDataCenterService.DataLoaderService.OnLoadDataCompleted += OnLoadDataCompleted;
}
private void OnLoadDataCompleted(object? sender, DataLoadCompletedEventArgs e)
{
_reloadSemaphore.Release();
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("S7后台服务正在启动。");
try
{
while (!stoppingToken.IsCancellationRequested)
{
await _reloadSemaphore.WaitAsync(stoppingToken); // Wait for a reload signal
if (stoppingToken.IsCancellationRequested)
{
break;
}
if (_appDataStorageService.Devices.IsEmpty)
{
_logger.LogInformation("没有可用的S7设备等待设备列表更新...");
continue;
}
await LoadAndInitializeDevicesAsync(stoppingToken);
_logger.LogInformation("S7后台服务已启动。");
// 持续轮询,直到取消请求或需要重新加载
while (!stoppingToken.IsCancellationRequested && _reloadSemaphore.CurrentCount == 0)
{
await PollAllDevicesAsync(stoppingToken);
await Task.Delay(_s7PollOnceSleepTimeMs, stoppingToken);
}
}
}
catch (OperationCanceledException)
{
_logger.LogInformation("S7后台服务已停止。");
}
catch (Exception e)
{
_logger.LogError(e, $"S7后台服务运行中发生了错误:{e.Message}");
}
finally
{
await CleanupAsync();
}
}
/// <summary>
/// 加载并初始化所有S7设备
/// </summary>
private async Task LoadAndInitializeDevicesAsync(CancellationToken stoppingToken)
{
try
{
_logger.LogInformation("开始加载S7设备....");
// 获取所有激活的S7设备
var s7Devices = _appDataStorageService
.Devices.Values.Where(d => d.Protocol == ProtocolType.S7 && d.IsActive == true)
.ToList();
// 清理已不存在的设备代理
var existingDeviceIds = s7Devices.Select(d => d.Id).ToHashSet();
var agentKeysToRemove = _activeAgents.Keys.Where(id => !existingDeviceIds.Contains(id)).ToList();
foreach (var deviceId in agentKeysToRemove)
{
if (_activeAgents.TryRemove(deviceId, out var agent))
{
await agent.DisposeAsync();
_logger.LogInformation($"已移除设备ID {deviceId} 的代理");
}
}
// 为每个设备创建或更新代理
foreach (var deviceDto in s7Devices)
{
if (!_appDataStorageService.Devices.TryGetValue(deviceDto.Id, out var device))
continue;
// 创建或更新设备代理
// await CreateOrUpdateAgentAsync(device, stoppingToken);
}
_logger.LogInformation($"S7设备加载成功共加载S7设备{s7Devices.Count}个");
}
catch (Exception e)
{
_logger.LogError(e, $"加载S7设备的过程中发生了错误{e.Message}");
}
}
/// <summary>
/// 创建或更新设备代理
/// </summary>
private async Task CreateOrUpdateAgentAsync(Device device, CancellationToken stoppingToken)
{
try
{
// 获取设备的变量
var variables = device.VariableTables?
.SelectMany(vt => vt.Variables)
.Where(v => v.IsActive == true && v.Protocol == ProtocolType.S7)
.ToList() ?? new List<Variable>();
// 检查是否已存在代理
if (_activeAgents.TryGetValue(device.Id, out var existingAgent))
{
// 更新现有代理的变量配置
existingAgent.UpdateVariables(variables);
}
else
{
// 创建新的代理
// // var agent = new S7DeviceAgent(device, _channelBus, _messenger, _logger);
// _activeAgents.AddOrUpdate(device.Id, agent, (key, oldValue) => agent);
//
// // 连接设备
// await agent.ConnectAsync();
//
// // 更新变量配置
// agent.UpdateVariables(variables);
_logger.LogInformation($"已为设备 {device.Name} (ID: {device.Id}) 创建代理");
}
}
catch (Exception ex)
{
_logger.LogError(ex, $"为设备 {device.Name} (ID: {device.Id}) 创建/更新代理时发生错误");
}
}
/// <summary>
/// 轮询所有设备
/// </summary>
private async Task PollAllDevicesAsync(CancellationToken stoppingToken)
{
try
{
var pollTasks = new List<Task>();
// 为每个活动代理创建轮询任务
foreach (var agent in _activeAgents.Values)
{
if (stoppingToken.IsCancellationRequested)
break;
pollTasks.Add(agent.PollVariablesAsync());
}
// 并行执行所有轮询任务
await Task.WhenAll(pollTasks);
}
catch (Exception ex)
{
_logger.LogError(ex, $"轮询S7设备时发生错误{ex.Message}");
}
}
/// <summary>
/// 清理资源
/// </summary>
private async Task CleanupAsync()
{
_logger.LogInformation("正在清理S7后台服务资源...");
// 断开所有代理连接并释放资源
var cleanupTasks = new List<Task>();
foreach (var agent in _activeAgents.Values)
{
cleanupTasks.Add(agent.DisposeAsync().AsTask());
}
await Task.WhenAll(cleanupTasks);
_activeAgents.Clear();
_logger.LogInformation("S7后台服务资源清理完成");
}
}