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

如何在运行中的C# OPC UA Server动态添加节点?

OPC UA服务器运行时动态添加节点的实现方案

一、服务器端直接创建(推荐方案)

既然你是从MQTT、Socket这类外部进程获取数据,直接在服务器端处理比走客户端调用流程更高效,也更贴合OPC UA的架构逻辑。

实现步骤

  1. 监听MQTT/Socket的数据流,解析出节点关键信息:节点ID、显示名称、父节点ID、数据类型等
  2. 在自定义的CustomNodeManager2实例中,调用内置API创建并添加节点
  3. 触发地址空间变更通知,让客户端能实时感知到新节点

代码示例

// 假设你的自定义节点管理器是MyNodeManager,已完成初始化
public void AddDynamicNode(string nodeIdStr, string displayName, NodeId parentNodeId, NodeId dataTypeId)
{
    // 构建节点属性
    var varAttrs = new VariableAttributes
    {
        DisplayName = new LocalizedText(displayName),
        Description = new LocalizedText("从外部数据源同步的动态节点"),
        AccessLevel = AccessLevels.CurrentRead | AccessLevels.CurrentWrite,
        UserAccessLevel = AccessLevels.CurrentRead | AccessLevels.CurrentWrite,
        DataType = dataTypeId,
        ValueRank = ValueRanks.Scalar,
        Historizing = false
    };

    // 生成节点ID(注意命名空间索引要和你的节点管理器匹配)
    var newNodeId = new NodeId(nodeIdStr, MyNodeManager.NamespaceIndex);

    // 创建变量节点实例
    var variableNode = new VariableNode(
        MyNodeManager.Server.DefaultNodeManager,
        newNodeId,
        new QualifiedName(displayName, MyNodeManager.NamespaceIndex),
        newNodeId,
        varAttrs);

    // 添加到地址空间
    MyNodeManager.AddNode(variableNode);

    // 关联到父节点并触发变更通知
    if (MyNodeManager.FindNode(parentNodeId) is BaseObjectNode parentNode)
    {
        parentNode.AddChild(variableNode);
        MyNodeManager.Server.FireNodeChangeNotification(new NodeChangeNotificationEventArgs(NodeChangeType.Added, variableNode));
    }
}

之后你只需要在MQTT的消息回调或者Socket的数据接收方法里,调用这个AddDynamicNode方法,传入解析好的参数即可。

二、客户端调用AddNodes()的正确姿势

如果你一定要用客户端方式添加节点,需要注意SessionClient的调用规范,同时确保服务器开启了相应权限。

代码示例

// 假设已成功建立OPC UA客户端会话
public async Task AddNodeThroughClient(SessionClient session, string nodeIdStr, string displayName, NodeId parentNodeId)
{
    var addItem = new AddNodesItem
    {
        ParentNodeId = parentNodeId,
        ReferenceTypeId = ReferenceTypeIds.Organizes,
        RequestedNewNodeId = new NodeId(nodeIdStr, 2), // 替换为你的命名空间索引
        BrowseName = new QualifiedName(displayName, 2),
        NodeClass = NodeClass.Variable,
        NodeAttributes = new VariableAttributes
        {
            DisplayName = new LocalizedText(displayName),
            DataType = DataTypeIds.Double, // 根据实际数据类型调整
            AccessLevel = AccessLevels.CurrentRead,
            UserAccessLevel = AccessLevels.CurrentRead,
            ValueRank = ValueRanks.Scalar
        },
        TypeDefinitionId = VariableTypeIds.BaseDataVariableType
    };

    var request = new AddNodesRequest
    {
        NodesToAdd = new[] { addItem }
    };

    try
    {
        var response = await session.AddNodesAsync(request);
        if (response.Results[0].StatusCode.IsGood())
        {
            Console.WriteLine("节点添加成功");
        }
        else
        {
            Console.WriteLine($"添加失败:{response.Results[0].StatusCode}");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"添加出错:{ex.Message}");
    }
}

注意事项:

  • 服务器配置中需开启SecurityConfiguration.AllowModifyAddresses = true
  • 客户端会话必须拥有Modify权限,否则会被服务器拒绝操作

三、可用辅助库

  • Opc.Ua.Server:你正在使用的官方库,自带的API完全能满足需求,无需额外依赖
  • MQTTnet:轻量级MQTT处理库,可快速实现MQTT客户端,接收数据后直接调用服务器端节点添加方法
  • SocketAsyncEventArgs:.NET原生高效Socket处理类,适合高并发数据流场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 11:35:20