Version: OPCFoundation.NetStandard.Opc.Ua.Server 2.0.0-preview.4
A Method that comes out of a NodeSet2 document loaded with AddRuntimeNodeSet /
AddRuntimeNodeSetAsync keeps its InputArguments Property as an untyped
PropertyState child. MethodState.InputArguments — the typed
PropertyState<ArrayOf<Argument>> that Call validates against — stays null, so the
server believes the Method declares no arguments and answers BadTooManyArguments to
every call that carries one.
The value itself imports correctly: a Client that reads the InputArguments Property gets
the arguments the document declares. Only the binding to the typed property is missing.
Repro
ModelControl.NodeSet2.xml, a Method with one String argument:
<UAMethod NodeId="ns=1;i=1010" BrowseName="1:Load" ParentNodeId="ns=1;i=1000">
<DisplayName>Load</DisplayName>
<References>
<Reference ReferenceType="HasProperty">ns=1;i=1011</Reference>
<Reference ReferenceType="HasComponent" IsForward="false">ns=1;i=1000</Reference>
</References>
</UAMethod>
<UAVariable NodeId="ns=1;i=1011" BrowseName="InputArguments" ParentNodeId="ns=1;i=1010"
DataType="Argument" ValueRank="1" ArrayDimensions="1">
<DisplayName>InputArguments</DisplayName>
<References>
<Reference ReferenceType="HasTypeDefinition">i=68</Reference>
<Reference ReferenceType="HasProperty" IsForward="false">ns=1;i=1010</Reference>
</References>
<Value>
<ListOfExtensionObject xmlns="http://opcfoundation.org/UA/2008/02/Types.xsd">
<ExtensionObject>
<TypeId><Identifier>i=297</Identifier></TypeId>
<Body><Argument><Name>revision</Name>
<DataType><Identifier>i=12</Identifier></DataType>
<ValueRank>-1</ValueRank><ArrayDimensions />
</Argument></Body>
</ExtensionObject>
</ListOfExtensionObject>
</Value>
</UAVariable>
In the RuntimeNodeSetOptions.Configure hook:
MethodState load = builder.Node<MethodState>("ModelControl/Load").Node;
// load.InputArguments is null
// GetChildren reports one PropertyState named "InputArguments" with the right value
Calling Load("Rev1") then answers BadTooManyArguments; calling a Method that declares
no arguments works.
Workaround
NodeState.CreateChild with createOrReplace builds the typed Property and assigns it —
PropertyState<T> is abstract, so it cannot be constructed directly:
var children = new List<BaseInstanceState>();
method.GetChildren(context, children);
BaseVariableState imported = children
.OfType<BaseVariableState>()
.FirstOrDefault(c => c.BrowseName.Name == BrowseNames.InputArguments);
if (imported != null && method.InputArguments == null)
{
bool decoded = imported.WrappedValue.TryGetValue(out ArrayOf<ExtensionObject> encoded);
method.RemoveChild(imported);
method.CreateChild(context, new QualifiedName(BrowseNames.InputArguments), true);
method.InputArguments.NodeId = imported.NodeId;
method.InputArguments.DisplayName = imported.DisplayName;
method.InputArguments.Value = decoded ? ExtensionObject.ToArray<Argument>(encoded) : default;
}
Prior art
#1056 reported the same symptom in 2022 for a hand-rolled UANodeSet.Import and was
closed as not planned, with the note "I think we need to provide a helper function and
samples in the server to do this."
The situation has changed: AddRuntimeNodeSet is now a first-class API whose whole purpose
is to host a vendor NodeSet2 document, and a vendor document that declares Methods with
arguments is ordinary. Every server that loads one needs the six lines above, which reach
into CreateChild semantics most callers should not have to know about. Doing the binding
inside the NodeSet2 import — or shipping the helper #1056 asked for — would remove that.
OutputArguments presumably needs the same treatment; this sample only exercises inputs.
Version:
OPCFoundation.NetStandard.Opc.Ua.Server2.0.0-preview.4A Method that comes out of a NodeSet2 document loaded with
AddRuntimeNodeSet/AddRuntimeNodeSetAsynckeeps itsInputArgumentsProperty as an untypedPropertyStatechild.MethodState.InputArguments— the typedPropertyState<ArrayOf<Argument>>thatCallvalidates against — staysnull, so theserver believes the Method declares no arguments and answers
BadTooManyArgumentstoevery call that carries one.
The value itself imports correctly: a Client that reads the
InputArgumentsProperty getsthe arguments the document declares. Only the binding to the typed property is missing.
Repro
ModelControl.NodeSet2.xml, a Method with one String argument:In the
RuntimeNodeSetOptions.Configurehook:Calling
Load("Rev1")then answersBadTooManyArguments; calling a Method that declaresno arguments works.
Workaround
NodeState.CreateChildwithcreateOrReplacebuilds the typed Property and assigns it —PropertyState<T>is abstract, so it cannot be constructed directly:Prior art
#1056 reported the same symptom in 2022 for a hand-rolled
UANodeSet.Importand wasclosed as not planned, with the note "I think we need to provide a helper function and
samples in the server to do this."
The situation has changed:
AddRuntimeNodeSetis now a first-class API whose whole purposeis to host a vendor NodeSet2 document, and a vendor document that declares Methods with
arguments is ordinary. Every server that loads one needs the six lines above, which reach
into
CreateChildsemantics most callers should not have to know about. Doing the bindinginside the NodeSet2 import — or shipping the helper #1056 asked for — would remove that.
OutputArgumentspresumably needs the same treatment; this sample only exercises inputs.