You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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视图

OPC UA视图

已尝试操作

  • 查找导入相关资料
  • 查找示例项目

预期结果

  • 在Objects文件夹下看到DeviceSet节点

问题分析与解决方法

你的代码已成功导入DeviceSet节点,但缺少将它关联到Objects文件夹的关键引用关系。DI规范虽定义DeviceSet默认挂载在Objects下,但导入Nodeset后需手动建立引用。

  1. 添加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);
}
  1. 验证节点导入状态
    可在导入后打印PredefinedNodes.Count确认节点是否真的被导入,避免因文件路径或权限问题导致导入失败。

  2. 检查命名空间注册
    虽然代码中已做命名空间索引注册,但可在服务器启动时输出SystemContext.NamespaceUris列表,确认DI规范的命名空间已正确加入。

修改后重启服务器,再用OPC UA Viewer连接,即可在Objects文件夹下看到DeviceSet节点。

内容的提问来源于stack exchange,提问作者Teo230

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 04:01:27