.NET Based OPC UA Client/Server SDK
3.0.7.484
|
The BaseNodeManager implements all of the manager interfaces and provides access to a set of in-memory Nodes. It also provides functions that can be overloaded by a subclass to access data for some or all of the in-memory Nodes or to generate events based on application specific logic.
The BaseNodeManager uses UInt32 values called handle types to control how Node attributes are accessed. The user can set the handle type when the Node is created (via one of the Create<NodeClass> overloads) or with the SetNodeAttributeConfiguration or SetVariableConfiguration methods. The following handle types are supported by the BaseNodeManager:
The InternalPolled handle type allows the use of reflection to link user defined classes to an information model. This requires that the class properties are decorated with the UaInstanceDeclaration attribute such as shown in the following code snippet:
This class could be associated with any Object Node with a TypeDefinition FileType. The value of the OpenCount Variable Node would be mapped to the OpenCount property.
If an attribute value is a LocalizedText, then the user can tell the SDK to automatically translate the text with the ResourceManager by specifying a value for the Key property. The translation occurs when the value is added to the queue of a MonitoredItem.
The following methods can be overridden by the subclass to customize I/O operations:
The BaseNodeManager maintains an in memory representation of the notifier hierarchy. It is optimized to allow for fast propagation of events up the hierarchy. The AddNotifier method can be used to add new notifiers to this cache; however, this is also done automatically whenever a HasNotifier reference is added via AddNode or AddReference methods (or via any of the Create<NodeClass> methods).
This cache allows applications to create events once, set the source and call the BaseNodeManager ReportEvent method. The SDK will take care of walking up the hierarchy and reporting the event to every currently active MonitoredItem.
An event created with a Server is an instance of a GenericEvent class. This class requires an instance of FilterManager (a property on the ServerManager instance). The FilterManager assigns handles to all known sequences of BrowseNames (also called a BrowsePath). Events that are created rarely can be populated with the Set methods that take a hardcoded BrowsePath as an argument as shown in the following code snippet:
The first argument of the LocalizedText constructor is a key that is used by the ResourceManager to look up translations of the default text. If no translation is found, the default text is used. This allows the framework to automatically translate the LocalizedText into the locales required by different MonitoredItems.
The Initialize method is used to set the event fields required to process the event within the SDK (EventId, EventType, SourceNode and Time). If any mandatory field is set to null, a suitable default is chosen. If the four required fields need to be overridden, the properties on the GenericEvent object need to be set explicitly. Calling the Set method will mean the SDK will not see the changes.
If an event is created over and over again, the user should register the BrowsePath with the FilterManager.CreateFieldHandle method and save the handle returned. When a new instance of the event is created, the field values should be set using this saved handle. The code generated by the UaModeler includes code to save and use these handles when filling in an event.
The BaseNodeManager also provides methods which are called when operations are performed on notifiers in the hierarchy that can affect the state of nodes below it. These methods are summarized in the following:
The SDK also provides helper classes for all of the OPC UA defined event types such as AlarmType.
The classes can be used to store “templates” for events that can be raised over and over. The following snippet initializes one of these classes (by convention the class name is the same as the event type except “Type” is replaced with “Model”):
The following code snippet will raise an event based on the in memory object:
These convenience classes can be created for a user defined information model with the UaModeler tool that can be downloaded from the Unified Automation website.
The BaseNodeManager implements the Call service for Objects which belong to the NodeManager. The Method is expected to be in the same NodeManager or the Method defined on the TypeDefinition for the Object.
When the GetMethodHandle method is called, a delegate for the method implementation needs to be found. First, the BaseNodeManager looks in the UserData associated with the Object Node (set by calling the SetNodeUserData method). If the UserData supports the IMethodDispatcher interface, then GetMethodDispatcher is called on the UserData. Otherwise, the GetMethodDispatcher method on the BaseNodeManager is called. If GetMethodDispatcher returns a null, then a Bad_NotImplemented error will be returned to the Client.
When the FinishCallTransaction method is called by the ServerManager, the BaseNodeManager will call the CallMethod method for each operation in the transaction. This method validates the input arguments by checking the number and the data type. It also creates an array of output arguments which are initialized with the default values for the data type.
The BaseNodeManager finds the input and output arguments by reading the value of the InputArguments and OutputArguments properties of the Method Node. For better performance these properties should be stored in memory.
If the input arguments are valid, the delegate returned by GetMethodDispatcher is called. If this method throws an exception, it is caught and an error status is returned for the operation. The implementer of the method does not need to check the number and type of arguments since the caller has already done this. Other checks may be required depending on the method call.
The following code snippet illustrates how to implement the IMethodDispatcher on an Object that can be set as the UserData for a Node.
The SDK includes an implementation of IMethodDispatcher for UA defined ObjectTypes such as AlarmTypes. This implementation invokes methods on an interface (called I<TypeName>Methods) containing all methods defined for the ObjectType.
These standard IMethodDispatcher implementations can be created for a user defined information model with the UaModeler tool that can be downloaded from the Unified Automation website.
The BaseNodeManager allows users to create or delete nodes and references using the INodeManagementManager interface. In addition, BaseNodeManager provides simplified helper functions that create instances for each NodeClass (the Create<NodeClass> methods).
When creating Objects or Variables, the BaseNodeManager automatically creates all of the mandatory instances required by the TypeDefinition. The user can request that optional instances are created as well by setting the OptionalBrowsePaths property. The BaseNodeManager determines the structure of the TypeDefinition by browsing the Server address space using the InternalClient object. It caches any results found to improve the performance of subsequent instantiations of the same TypeDefinition.
When Objects or Variables are instantiated, the child Nodes need NodeIds assigned. The NodeIdGenerationSettings property controls the behavior. There are basically two modes that depend on whether a string identifier was passed in as the RequestedNodeId. If the RequestedNodeId has a string, then the NodeIds of the components are constructed by appending the delimiter specified in the settings and the name portion of the BrowseName. If the RequestedNodeId has a type other than string, then new identifiers are created by generating Guids or incrementing a counter in the settings.
Nodes can also be added to the BaseNodeManager with the ImportUaNodeSet method. This method reads an XML document from a file or a stream that conforms to the UANodeSet schema. During import any reverse references are added, any notifiers are indexed and any new namespace URIs are added to the Server’s namespace table. This method will also register the BaseNodeManager doing the import as the NodeManager for URIs used by the NodeIds of Nodes defined in the document.
ServerInternalClient is a class that calls the same methods that the ServerManager calls, however, it provides an API that can be used by other components of the Server process. The primary APIs are as follows:
The caller passes a delegate into the CreateDataMonitoredItems method which is called whenever a data change occurs so there is no need for the Subscribe and Publish services.
The ServerInternalClient also provides the following helper methods:
The helper methods use the Read, Write, Browse and Translate methods, however, this is often an inefficient way to get the information for some NodeManagers (such as NodeManagers which inherit from BaseNodeManager). For this reason the SDK defines the IAdvancedNodeManager interface which allows a NodeManager to directly implement these functions. If the IAdvancedNodeManager interface is not defined on the NodeManager associated with the Node, then the default method is used.