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

基于OPC UA Foundation仓库的.NET服务器添加OnRead方法求助

解决OPC UA .NETStandard SampleServer动态处理Read请求并创建节点的问题

在OPC UA .NETStandard框架中,SampleServer及其父类没有直接暴露OnRead方法,但可以通过两种方式实现Read请求的拦截和动态节点创建:

方案一:在SampleServer中覆盖请求处理方法

直接在你的SampleServer类中重写ProcessRequestAsync,识别Read请求并处理缺失节点:

protected override async Task<IServiceResponse> ProcessRequestAsync(IServiceRequest request, RequestHeader requestHeader, Session session)
{
    if (request is ReadRequest readRequest)
    {
        // 遍历所有待读取节点,检查是否存在
        foreach (var nodeToRead in readRequest.NodesToRead)
        {
            var targetNodeId = nodeToRead.NodeId;
            if (!ServerCore.NodeManager.IsNodeIdKnown(targetNodeId))
            {
                // 动态创建缺失的节点
                await CreateDynamicNodeAsync(targetNodeId);
            }
        }
    }
    // 交给基类处理后续请求逻辑
    return await base.ProcessRequestAsync(request, requestHeader, session);
}

// 动态创建节点的辅助方法
private async Task CreateDynamicNodeAsync(NodeId nodeId)
{
    // 获取自定义的SampleNodeManager(根据你的实际类名调整)
    var sampleNodeManager = (SampleNodeManager)ServerCore.NodeManager;
    
    // 创建一个示例变量节点(可根据需求修改节点类型、数据类型等)
    var dynamicVariable = new VariableNode(
        sampleNodeManager,
        nodeId,
        new QualifiedName(nodeId.Identifier.ToString(), sampleNodeManager.NamespaceIndex),
        new LocalizedText("en-US", $"Dynamic Node: {nodeId.Identifier}"),
        null,
        new DataValue(0), // 初始值
        NodeId.Parse("i=63"), // 数据类型:Int32
        NodeId.Parse("i=63"), // 数据类型定义
        NodeId.Parse("i=58")  // 访问权限:可读可写
    );
    
    // 将节点添加到NodeManager
    await sampleNodeManager.AddNodeAsync(dynamicVariable);
}

方案二:在自定义NodeManager中覆盖节点读取方法

如果你的业务逻辑更贴近节点管理,推荐在SampleNodeManager中重写ReadNodesAsync方法,直接在节点管理层面处理:

public override async Task<ReadResponseCollection> ReadNodesAsync(ReadContext context, ReadValueIdCollection nodesToRead, TimestampsToReturn timestampsToReturn)
{
    // 预处理缺失节点
    foreach (var nodeToRead in nodesToRead)
    {
        var targetNodeId = nodeToRead.NodeId;
        if (!IsNodeIdKnown(targetNodeId))
        {
            await CreateDynamicNodeAsync(targetNodeId);
        }
    }
    // 调用基类完成读取操作
    return await base.ReadNodesAsync(context, nodesToRead, timestampsToReturn);
}

// 动态创建节点的辅助方法
private async Task CreateDynamicNodeAsync(NodeId nodeId)
{
    var dynamicVariable = new VariableNode(
        this,
        nodeId,
        new QualifiedName(nodeId.Identifier.ToString(), NamespaceIndex),
        new LocalizedText("en-US", $"Dynamic Node: {nodeId.Identifier}"),
        null,
        new DataValue(0),
        NodeId.Parse("i=63"),
        NodeId.Parse("i=63"),
        NodeId.Parse("i=58")
    );
    
    await AddNodeAsync(dynamicVariable);
}

关键说明

  • 框架设计原因:OPC UA .NETStandard没有直接提供OnRead钩子,而是通过服务请求处理、NodeManager节点管理的分层设计来扩展功能。
  • 命名空间注意:确保动态节点的NodeId命名空间索引与你的SampleNodeManager一致,否则会无法被正确管理。
  • 节点类型扩展:上述示例创建的是变量节点,你可以根据需求修改为对象、方法等其他OPC UA节点类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 09:35:32