Skip to content

Fluent node manager: pre-creation monitored-item hook (refuse or substitute a custom MonitoredItem) #4399

Description

@romanett

Summary

The fluent node manager can observe a monitored item only after the default sampled item has been created (INodeBuilder.OnMonitoredItemCreated). There is no fluent way to take part in the creation itself: to refuse a request (unsupported filter, index range, or encoding) with the proper status code, or to substitute a custom MonitoredItem implementation that pushes values directly instead of being sampled. Managers that need this keep overriding the CreateMonitoredItemAsync family on AsyncCustomNodeManager.

Where the limit is

  • src/Opc.Ua.Server/NodeManager/AsyncCustomNodeManager.cs: CreateMonitoredItemAsync (~6461) is the virtual that decides everything: it validates the filter, calls ReadInitialValue (~6537), creates the sampled item, and only then calls OnMonitoredItemCreated (~6550). By the time the fluent hook fires, a refusal or substitution is no longer possible.
  • src/Opc.Ua.Server/Fluent/FluentDelegates.cs: MonitoredItemCreatedHandler receives an ISampledDataChangeMonitoredItem, i.e. it is post-creation by type.
  • src/Opc.Ua.Server/Fluent/IFluentDispatcher.cs: no pre-creation route.
  • The generated partial (NodeManagerTemplates.cs) does not override CreateMonitoredItemAsync, so a user partial can, but that is the pre-fluent pattern and it cannot be expressed per node.

Who needs it (from the UA-.NETStandard-Samples audit)

Sample What it does at creation time
Opc.Ua.Sample/MemoryBuffer Refuses filters (BadFilterNotAllowed), index ranges (BadIndexRangeInvalid) and encodings (BadDataEncodingUnsupported) at creation; creates its own MemoryBufferMonitoredItem : MonitoredItem that carries the node handle and is fed by the buffer's scan loop; overrides modify, delete and set-monitoring-mode to keep that item in sync. The sample tests assert those three status codes at creation, so the default sampled path (which accepts filters) cannot be used
Workshop/PerfTest Subscribes register slices in the batch OnCreateMonitoredItemsComplete and pushes DataValues straight into IDataChangeMonitoredItem2.QueueValue every 45 ms for half a register, deliberately bypassing sampling; that push is the point of the sample
Workshop/Aggregation Overrides the public CreateMonitoredItemsAsync because the batch completion hook is synchronous and it needs to await the downstream subscription

Proposal

A pre-creation hook on the builder that can refuse or substitute, addressable per node, per type definition, or for a family of virtual nodes:

builder.Node("Buffers/UInt32")
    .OnCreateMonitoredItem((ISystemContext ctx, NodeHandle handle, MonitoredItemCreateRequest request) =>
    {
        if (request.RequestedParameters.Filter != null) return MonitoredItemDecision.Refuse(StatusCodes.BadFilterNotAllowed);
        if (request.ItemToMonitor.ParsedIndexRange != NumericRange.Empty) return MonitoredItemDecision.Refuse(StatusCodes.BadIndexRangeInvalid);
        return MonitoredItemDecision.Use(buffer.CreateDataChangeItem(handle, request));   // custom IMonitoredItem
        // or MonitoredItemDecision.Default() to fall through to the sampled item
    });
  • FluentNodeManagerBase (generated partial and FluentNodeManager) would override CreateMonitoredItemAsync and consult the dispatcher before the default path runs.
  • A substituted item must still flow through the existing modify / delete / set-monitoring-mode plumbing, so this pairs with the lifecycle hooks proposed separately (OnMonitoredItemModified / Deleted / OnMonitoringModeChanged).
  • An async batch OnCreateMonitoredItemsCompleteAsync (the existing OnCreateMonitoredItemsComplete is sync) would cover the Aggregation and PerfTest batch cases without a public-method override.
  • For push-style sources the handler needs a way to hand values to the item later; exposing the created IDataChangeMonitoredItem2 (or an IValueUpdater-like handle bound to the item rather than to the node) from the decision would let PerfTest keep its direct-queue push under the fluent surface.

Related: #4397 (on-demand nodes), #4398 (monitored-item lifecycle hooks).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementAPI or feature enhancement

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions