.NET 8 OPC UA Server导入DI NodeSet后DeviceSet节点不显示
.NET 8 OPC UA Server导入DI规范Nodeset后DeviceSet节点未显示
我正在进行个人项目,基于.NET 8搭建OPC UA Server,需要引入外部Nodeset。导入包含DI规范(OPC 10000-100: 设备)Nodeset信息的Xml文件时遇到问题:按规范描述,DeviceSet节点应自动显示在任意OPC UA Viewer的Objects文件夹下,但实际并未出现。
自定义节点管理器代码
MainNodeManager.cs
using Microsoft.Extensions.Configuration; using Opc.Ua; using Opc.Ua.Export; using Opc.Ua.Server; using System.Reflection; using OpcUaServerSample.Host.OPCUA; namespace OpcUaServerSample.Host.NodeManagers { public class MainNodeManager : CustomNodeManager2 { private IDictionary<NodeId, IList<IReference>> m_externalReferences; private ILogger _logger; private OpcUaServerConfiguration m_configuration; private static readonly string[] ModelNamespaceUris = new string[] { OPCUA.Namespaces.OpcUaServer }; public MainNodeManager(ILogger logger, IServerInternal server, ApplicationConfiguration configuration) : base(server, ModelNamespaceUris) { _logger = logger; SystemContext.NodeIdFactory = this; // 获取节点管理器的配置 m_configuration = configuration.ParseExtension<OpcUaServerConfiguration>() ?? new(); } public override void CreateAddressSpace(IDictionary<NodeId, IList<IReference>> externalReferences) { lock (Lock) { m_externalReferences = externalReferences; IList<IReference> references = null; if (!externalReferences.TryGetValue(ObjectIds.ObjectsFolder, out references)) { externalReferences[ObjectIds.ObjectsFolder] = references = new List<IReference>(); } try { ImportXml(externalReferences, "NodeSets\\Opc.Ua.Di.NodeSet2.xml"); } catch (Exception ex) { _logger.LogError("导入Nodeset时出错", ex); } NodeState deviceSetNode = PredefinedNodes.Values.First(x => x.BrowseName.Name == "DeviceSet"); base.CreateAddressSpace(externalReferences); } } private void ImportXml(IDictionary<NodeId, IList<IReference>> externalReferences, string resourcepath) { try { NodeStateCollection predefinedNodes = new NodeStateCollection(); Stream stream = new FileStream(resourcepath, FileMode.Open); UANodeSet nodeSet = UANodeSet.Read(stream); foreach (string namespaceUri in nodeSet.NamespaceUris) { SystemContext.NamespaceUris.GetIndexOrAppend(namespaceUri); } nodeSet.Import(SystemContext, predefinedNodes); for (int ii = 0; ii < predefinedNodes.Count; ii++) { AddPredefinedNode(SystemContext, predefinedNodes[ii]); } // 确保反向引用存在 AddReverseReferences(externalReferences); _logger.LogInformation($"已导入NodeSet {nodeSet.NamespaceUris[0]}"); } catch (Exception ex) { _logger.LogError("NodeSetImportNodeManager.Import: 加载node set出错", ex); throw; } } } }
当前OPC UA视图

已尝试操作
- 查找导入相关资料
- 查找示例项目
预期结果
- 在Objects文件夹下看到DeviceSet节点
问题分析与解决方法
你的代码已成功导入DeviceSet节点,但缺少将它关联到Objects文件夹的关键引用关系。DI规范虽定义DeviceSet默认挂载在Objects下,但导入Nodeset后需手动建立引用。
- 添加DeviceSet到Objects文件夹的Organizes引用
修改CreateAddressSpace方法,在导入Nodeset后添加引用:
try { ImportXml(externalReferences, "NodeSets\\Opc.Ua.Di.NodeSet2.xml"); // 找到DeviceSet节点 NodeState deviceSetNode = PredefinedNodes.Values.First(x => x.BrowseName.Name == "DeviceSet"); // 添加从Objects文件夹到DeviceSet的Organizes引用 references.Add(new NodeStateReference(ReferenceTypeIds.Organizes, false, deviceSetNode.NodeId)); } catch (Exception ex) { _logger.LogError("导入Nodeset时出错", ex); }
验证节点导入状态
可在导入后打印PredefinedNodes.Count确认节点是否真的被导入,避免因文件路径或权限问题导致导入失败。检查命名空间注册
虽然代码中已做命名空间索引注册,但可在服务器启动时输出SystemContext.NamespaceUris列表,确认DI规范的命名空间已正确加入。
修改后重启服务器,再用OPC UA Viewer连接,即可在Objects文件夹下看到DeviceSet节点。
内容的提问来源于stack exchange,提问作者Teo230
相关产品推荐
相关产品推荐

