1 实现 MQTT 变量数据发布功能
2 3 - 迁移 IMqttServiceManager 接口到 DMS.Core 4 - 在 DataCenterService 中添加 MQTT 服务器和变量别名的加载逻辑 5 - 实现 MqttPublishProcessor 的核心处理逻辑 6 - 为 DTO 和 ViewModel 的 MqttAliases 属性提供默认空列表初始化 7 - 更新 AutoMapper 映射配置以支持 VariableMqttAliasDto
This commit is contained in:
@@ -14,7 +14,7 @@ public class VariableDto
|
|||||||
public string DataValue { get; set; }
|
public string DataValue { get; set; }
|
||||||
public string DisplayValue { get; set; }
|
public string DisplayValue { get; set; }
|
||||||
public VariableTableDto? VariableTable { get; set; }
|
public VariableTableDto? VariableTable { get; set; }
|
||||||
public List<VariableMqttAliasDto>? MqttAliases { get; set; }
|
public List<VariableMqttAliasDto>? MqttAliases { get; set; } = new List<VariableMqttAliasDto>();
|
||||||
public SignalType SignalType { get; set; }
|
public SignalType SignalType { get; set; }
|
||||||
public int PollingInterval { get; set; }
|
public int PollingInterval { get; set; }
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ public class DataCenterService : IDataCenterService
|
|||||||
public event EventHandler<MqttServerChangedEventArgs> MqttServerChanged;
|
public event EventHandler<MqttServerChangedEventArgs> MqttServerChanged;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当变量值发生变化时触发
|
/// 当变量值发生变化时触发
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -202,7 +201,6 @@ public class DataCenterService : IDataCenterService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void RemoveDeviceFromMemory(int deviceId)
|
public void RemoveDeviceFromMemory(int deviceId)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (Devices.TryGetValue(deviceId, out var deviceDto))
|
if (Devices.TryGetValue(deviceId, out var deviceDto))
|
||||||
{
|
{
|
||||||
foreach (var variableTable in deviceDto.VariableTables)
|
foreach (var variableTable in deviceDto.VariableTables)
|
||||||
@@ -317,7 +315,6 @@ public class DataCenterService : IDataCenterService
|
|||||||
{
|
{
|
||||||
deviceDto = device;
|
deviceDto = device;
|
||||||
device.VariableTables.Remove(variableTableDto);
|
device.VariableTables.Remove(variableTableDto);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OnVariableTableChanged(new VariableTableChangedEventArgs(
|
OnVariableTableChanged(new VariableTableChangedEventArgs(
|
||||||
@@ -666,6 +663,8 @@ public class DataCenterService : IDataCenterService
|
|||||||
|
|
||||||
var mqttServers = await LoadAllMqttServersAsync();
|
var mqttServers = await LoadAllMqttServersAsync();
|
||||||
|
|
||||||
|
var variableMqttAliases = await _repositoryManager.VariableMqttAliases.GetAllAsync();
|
||||||
|
|
||||||
// 建立设备与变量表的关联
|
// 建立设备与变量表的关联
|
||||||
foreach (var deviceDto in deviceDtos)
|
foreach (var deviceDto in deviceDtos)
|
||||||
{
|
{
|
||||||
@@ -692,6 +691,12 @@ public class DataCenterService : IDataCenterService
|
|||||||
VariableTables.TryAdd(variableTableDto.Id, variableTableDto);
|
VariableTables.TryAdd(variableTableDto.Id, variableTableDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 加载MQTT服务器数据到内存
|
||||||
|
foreach (var mqttServer in mqttServers)
|
||||||
|
{
|
||||||
|
MqttServers.TryAdd(mqttServer.Id, mqttServer);
|
||||||
|
}
|
||||||
|
|
||||||
// 将变量添加到安全字典
|
// 将变量添加到安全字典
|
||||||
foreach (var variableDto in variableDtos)
|
foreach (var variableDto in variableDtos)
|
||||||
{
|
{
|
||||||
@@ -699,6 +704,22 @@ public class DataCenterService : IDataCenterService
|
|||||||
{
|
{
|
||||||
variableDto.VariableTable = variableTable;
|
variableDto.VariableTable = variableTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// var alises= variableMqttAliases.FirstOrDefault(vm => vm.VariableId == variableDto.Id);
|
||||||
|
// if (alises != null)
|
||||||
|
// {
|
||||||
|
//
|
||||||
|
// var variableMqttAliasDto = _mapper.Map<VariableMqttAliasDto>(alises);
|
||||||
|
// variableMqttAliasDto.Variable = _mapper.Map<Variable>(variableDto) ;
|
||||||
|
// if (MqttServers.TryGetValue(variableMqttAliasDto.MqttServerId, out var mqttServerDto))
|
||||||
|
// {
|
||||||
|
// variableMqttAliasDto.MqttServer = _mapper.Map<MqttServer>(mqttServerDto) ;
|
||||||
|
// variableMqttAliasDto.MqttServerName = variableMqttAliasDto.MqttServer.ServerName;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// variableDto.MqttAliases.Add(variableMqttAliasDto);
|
||||||
|
// }
|
||||||
|
|
||||||
Variables.TryAdd(variableDto.Id, variableDto);
|
Variables.TryAdd(variableDto.Id, variableDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,11 +729,7 @@ public class DataCenterService : IDataCenterService
|
|||||||
Menus.TryAdd(menuDto.Id, menuDto);
|
Menus.TryAdd(menuDto.Id, menuDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载MQTT服务器数据到内存
|
|
||||||
foreach (var mqttServer in mqttServers)
|
|
||||||
{
|
|
||||||
MqttServers.TryAdd(mqttServer.Id, mqttServer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建菜单树
|
// 构建菜单树
|
||||||
BuildMenuTree();
|
BuildMenuTree();
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using AutoMapper;
|
||||||
using DMS.Application.Interfaces;
|
using DMS.Application.Interfaces;
|
||||||
using DMS.Application.Models;
|
using DMS.Application.Models;
|
||||||
|
using DMS.Core.Interfaces.Services;
|
||||||
using DMS.Core.Models;
|
using DMS.Core.Models;
|
||||||
|
|
||||||
namespace DMS.Application.Services.Processors;
|
namespace DMS.Application.Services.Processors;
|
||||||
@@ -10,12 +12,14 @@ namespace DMS.Application.Services.Processors;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class MqttPublishProcessor : IVariableProcessor
|
public class MqttPublishProcessor : IVariableProcessor
|
||||||
{
|
{
|
||||||
// private readonly IMqttServiceManager _mqttServiceManager;
|
private readonly IMapper _mapper;
|
||||||
|
private readonly IMqttServiceManager _mqttServiceManager;
|
||||||
|
|
||||||
// public MqttPublishProcessor(IMqttServiceManager mqttServiceManager)
|
public MqttPublishProcessor(IMapper mapper, IMqttServiceManager mqttServiceManager)
|
||||||
// {
|
{
|
||||||
// // _mqttServiceManager = mqttServiceManager;
|
_mapper = mapper;
|
||||||
// }
|
_mqttServiceManager = mqttServiceManager;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 处理单个变量上下文,如果有关联的MQTT配置,则将其推送到发送队列。
|
/// 处理单个变量上下文,如果有关联的MQTT配置,则将其推送到发送队列。
|
||||||
@@ -23,25 +27,25 @@ public class MqttPublishProcessor : IVariableProcessor
|
|||||||
/// <param name="context">包含变量及其元数据的上下文对象。</param>
|
/// <param name="context">包含变量及其元数据的上下文对象。</param>
|
||||||
public async Task ProcessAsync(VariableContext context)
|
public async Task ProcessAsync(VariableContext context)
|
||||||
{
|
{
|
||||||
// var variable = context.Data;
|
var variable = context.Data;
|
||||||
// if (variable?.MqttAliases == null || variable.MqttAliases.Count == 0)
|
if (variable?.MqttAliases == null || variable.MqttAliases.Count == 0)
|
||||||
// {
|
{
|
||||||
// return; // 没有关联的MQTT配置,直接返回
|
return; // 没有关联的MQTT配置,直接返回
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// // 遍历所有关联的MQTT配置,并将其推入发送队列
|
// 遍历所有关联的MQTT配置,并将其推入发送队列
|
||||||
// foreach (var variableMqttAlias in variable.MqttAliases)
|
foreach (var variableMqttAlias in variable.MqttAliases)
|
||||||
// {
|
{
|
||||||
// // 创建VariableMqtt对象
|
// 创建VariableMqtt对象
|
||||||
// var variableMqtt = new VariableMqtt
|
var variableMqtt = new VariableMqtt
|
||||||
// {
|
{
|
||||||
// Variable = variable,
|
Variable = _mapper.Map<Variable>(variable),
|
||||||
// Mqtt = variableMqttAlias.MqttServer,
|
Mqtt = variableMqttAlias.MqttServer,
|
||||||
// MqttId = variableMqttAlias.MqttServerId
|
MqttId = variableMqttAlias.MqttServerId
|
||||||
// };
|
};
|
||||||
//
|
|
||||||
// // 发布变量数据到MQTT服务器
|
// 发布变量数据到MQTT服务器
|
||||||
// await _mqttServiceManager.PublishVariableDataAsync(variableMqtt);
|
await _mqttServiceManager.PublishVariableDataAsync(variableMqtt);
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,5 +15,11 @@ namespace DMS.Core.Interfaces.Repositories
|
|||||||
/// 异步根据变量和服务器获取别名关联。
|
/// 异步根据变量和服务器获取别名关联。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Task<VariableMqttAlias> GetByVariableAndServerAsync(int variableId, int mqttServerId);
|
Task<VariableMqttAlias> GetByVariableAndServerAsync(int variableId, int mqttServerId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取所有变量与MQTT别名关联。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>包含所有变量与MQTT别名关联实体的列表。</returns>
|
||||||
|
Task<List<VariableMqttAlias>> GetAllAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
using DMS.Core.Models;
|
using DMS.Core.Models;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace DMS.Infrastructure.Interfaces.Services
|
namespace DMS.Core.Interfaces.Services
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// MQTT服务管理器接口,负责管理MQTT连接和变量监控
|
/// MQTT服务管理器接口,负责管理MQTT连接和变量监控
|
||||||
@@ -10,6 +10,7 @@ using System.Threading.Tasks;
|
|||||||
using DMS.Application.DTOs.Events;
|
using DMS.Application.DTOs.Events;
|
||||||
using DMS.Core.Models;
|
using DMS.Core.Models;
|
||||||
using DMS.Application.Interfaces;
|
using DMS.Application.Interfaces;
|
||||||
|
using DMS.Core.Interfaces.Services;
|
||||||
|
|
||||||
namespace DMS.Infrastructure.Services
|
namespace DMS.Infrastructure.Services
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using DMS.Core.Models;
|
using DMS.Core.Models;
|
||||||
using DMS.Application.Interfaces;
|
using DMS.Application.Interfaces;
|
||||||
|
using DMS.Core.Interfaces.Services;
|
||||||
|
|
||||||
namespace DMS.Infrastructure.Services
|
namespace DMS.Infrastructure.Services
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace DMS.WPF.Profiles
|
|||||||
CreateMap<OpcUaNode, OpcUaNodeItemViewModel>()
|
CreateMap<OpcUaNode, OpcUaNodeItemViewModel>()
|
||||||
.ReverseMap();
|
.ReverseMap();
|
||||||
CreateMap<VariableItemViewModel, VariableItemViewModel>();
|
CreateMap<VariableItemViewModel, VariableItemViewModel>();
|
||||||
|
CreateMap<VariableMqttAliasDto, VariableMqttAliasItemViewModel>().ReverseMap();
|
||||||
|
|
||||||
|
|
||||||
CreateMap<MenuBeanDto, MenuItemViewModel>()
|
CreateMap<MenuBeanDto, MenuItemViewModel>()
|
||||||
|
|||||||
@@ -123,7 +123,11 @@ public partial class DataServices : ObservableObject, IRecipient<LoadMessage>, I
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void LoadAllDatas()
|
private void LoadAllDatas()
|
||||||
{
|
{
|
||||||
Devices = _mapper.Map<ObservableCollection<DeviceItemViewModel>>(_dataCenterService.Devices.Values);
|
|
||||||
|
foreach (var deviceDto in _dataCenterService.Devices.Values)
|
||||||
|
{
|
||||||
|
Devices.Add(_mapper.Map<DeviceItemViewModel>(deviceDto));
|
||||||
|
}
|
||||||
foreach (var device in Devices)
|
foreach (var device in Devices)
|
||||||
{
|
{
|
||||||
foreach (var variableTable in device.VariableTables)
|
foreach (var variableTable in device.VariableTables)
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public partial class VariableItemViewModel : ObservableObject
|
|||||||
/// 一个变量可以有多个MQTT别名。
|
/// 一个变量可以有多个MQTT别名。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private List<VariableMqttAliasItemViewModel>? _mqttAliases;
|
private List<VariableMqttAliasItemViewModel>? _mqttAliases=new List<VariableMqttAliasItemViewModel>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取或设置变量的信号类型 (如:AI, DI, AO, DO)。
|
/// 获取或设置变量的信号类型 (如:AI, DI, AO, DO)。
|
||||||
|
|||||||
48
QWEN.md
Normal file
48
QWEN.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# Project Overview: DMS (Device Management System)
|
||||||
|
|
||||||
|
This directory contains the source code for the Device Management System (DMS), a C#/.NET 8 application. The system is primarily composed of a WPF desktop application for the user interface, backed by a layered architecture including Core, Application, and Infrastructure projects. It also includes dedicated unit test projects for both the infrastructure and WPF layers.
|
||||||
|
|
||||||
|
A significant feature described in the README is an OPC UA service implementation, suggesting the system is designed for industrial device communication and management.
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
The solution (`DMS.sln`) is organized into several key projects:
|
||||||
|
|
||||||
|
* **`DMS.Core`**: Contains fundamental, reusable components and shared models. Likely includes utilities, common data transfer objects (DTOs), and core business logic abstractions. It references `Microsoft.Extensions.Logging.Abstractions`, `Newtonsoft.Json`, and `NLog`.
|
||||||
|
* **`DMS.Application`**: Implements application-specific business logic. It depends on `DMS.Core` and uses libraries like `AutoMapper` for object mapping and `Microsoft.Extensions` for hosting and logging abstractions.
|
||||||
|
* **`DMS.Infrastructure`**: Handles data access, external integrations, and technical implementations. It references `DMS.Core` and `DMS.Application`. Key dependencies include:
|
||||||
|
* `SqlSugarCore`: For database interaction (MySQL).
|
||||||
|
* `MQTTnet`: For MQTT protocol communication.
|
||||||
|
* `OPCFoundation.NetStandard.Opc.Ua`: For OPC UA communication.
|
||||||
|
* `S7netplus`: For Siemens S7 PLC communication.
|
||||||
|
* `NPOI`: For reading/writing Excel files.
|
||||||
|
* `AutoMapper.Extensions.Microsoft.DependencyInjection`: For dependency injection setup of AutoMapper.
|
||||||
|
* **`DMS.WPF`**: The main WPF desktop application. It targets `net8.0-windows` and uses WPF-specific libraries like `CommunityToolkit.Mvvm`, `HandyControl` (UI toolkit), `Hardcodet.NotifyIcon.Wpf` (system tray icon), and `iNKORE.UI.WPF.Modern` (modern UI styling). It depends on `DMS.Application` and `DMS.Infrastructure`.
|
||||||
|
* **`DMS.Infrastructure.UnitTests`**: Unit tests for the `DMS.Infrastructure` project. Uses `xunit`, `Moq`, `Bogus` (for fake data), and `Microsoft.NET.Test.Sdk`.
|
||||||
|
* **`DMS.WPF.UnitTests`**: Unit tests for the `DMS.WPF` project. Also uses `xunit`, `Moq`, and `Bogus`.
|
||||||
|
|
||||||
|
## Building and Running
|
||||||
|
|
||||||
|
This is a .NET 8 solution. You will need the .NET 8 SDK and an IDE like Visual Studio or JetBrains Rider to build and run it.
|
||||||
|
|
||||||
|
**To Build:**
|
||||||
|
Use the standard .NET CLI command within the solution directory:
|
||||||
|
`dotnet build`
|
||||||
|
|
||||||
|
**To Run:**
|
||||||
|
The main executable is the WPF application (`DMS.WPF`). You can run it using:
|
||||||
|
`dotnet run --project DMS.WPF`
|
||||||
|
|
||||||
|
**To Test:**
|
||||||
|
Unit tests are included in `DMS.Infrastructure.UnitTests` and `DMS.WPF.UnitTests`.
|
||||||
|
Run all tests using:
|
||||||
|
`dotnet test`
|
||||||
|
|
||||||
|
## Development Conventions
|
||||||
|
|
||||||
|
* **Language & Framework:** C# with .NET 8.
|
||||||
|
* **Architecture:** Layered architecture (Core, Application, Infrastructure) with a WPF presentation layer.
|
||||||
|
* **UI Pattern:** MVVM (Model-View-ViewModel), supported by `CommunityToolkit.Mvvm`.
|
||||||
|
* **DI (Dependency Injection):** Microsoft.Extensions.DependencyInjection is used, configured likely in the `DMS.WPF` project.
|
||||||
|
* **Logging:** NLog is used for logging, configured via `DMS.WPF\Configurations\nlog.config`.
|
||||||
|
* **Mapping:** AutoMapper is used for object-to-object mapping.
|
||||||
Reference in New Issue
Block a user