QuickOPC User's Guide and Reference
Navigation in the OPC UA data model
Extensions > Integrated Extensions > OPC UA Complex Data Extension > Advanced OPC UA Complex Data Tasks > Navigation in the OPC UA data model
In This Topic

For accessing the metadata about data types in OPC UA and navigating in it, the OPC UA Complex Data extension gives you

The providers retrieve the information from the OPC server in various ways (by reading and browsing the metadata nodes). In addition, they cache the information obtained. This is very important for performance reasons, because the same metadata can be reused without having to retrieve them from the server again and again.

OPC UA data type model provider

Take following steps to get access to the OPC UA data type model provider:

  1. Get the IEasyUAClientComplexData Interface service from your EasyUAClient Class instance using the GetService Method.
  2. Using the DataTypeModelProvider Property, obtain the IUADataTypeModelProvider Interface.

When you have the IUADataTypeModelProvider Interface, you can call its methods to:

The basic methods on the IUADataTypeModelProvider Interface provide just one navigation "hop" at a time. Some of these "hops" are, however, commonly needed together, in a chain, possibly with some kind of additional simple processing. For this purpose, there are extension methods available (in the IUADataTypeModelProviderExtension Class) that make such tasks easier. With help of these methods, you can then, for example:

If you have more pieces of information to work on in the same way, it is much more efficient to process them together, in one operation. All methods on the IUADataTypeModelProvider Interface and the IUADataTypeModelProviderExtension Class therefore accept a read-only list on input, and return an array of processed element on the output. If performance is not a concern, or if you have just one piece of information to work on at a time, there are extension methods to make it easier as well. For example, instead of calling GetDataTypeIdsFromModelNodeDescriptors Method for just one node, you can use the GetDataTypeIdFromModelNodeDescriptor Method instead.

OPC UA data type dictionary provider

This chapter only applies to the data type dictionary model, i.e. the only complex type model available before OPC UA 1.04. It does not apply to the data type definition model.

Take following steps to get access to the OPC UA data type dictionary provider:

  1. Get the IEasyUAClientComplexData Interface service from your EasyUAClient Class instance using the GetService Method.
  2. Using the DataTypeDictionaryProvider Property, obtain the IUADataTypeDictionaryProvider Interface.

When you have the IUADataTypeDictionaryProvider Interface, you can call its methods to:

The basic methods on the IUADataTypeDictionaryProvider Interface provide just one navigation "hop" at a time. Some of these "hops" are, however, commonly needed together, in a chain, possibly with some kind of additional simple processing. For this purpose, there are extension methods available (in the IUADataTypeDictionaryProviderExtension Class) that make such tasks easier. With help of these methods, you can then, for example:

If you have more pieces of information to work on in the same way, it is much more efficient to process them together, in one operation. All methods on the IUADataTypeDictionaryProvider Interface and the IUADataTypeDictionaryProviderExtension Class therefore accept a read-only list on input, and return an array of processed element on the output. If performance is not a concern, or if you have just one piece of information to work on at a time, there are extension methods to make it easier as well.

OPC UA data type definition provider

This chapter only applies to the data type definition model, i.e. the complex type model available since OPC UA 1.04. It does not apply to the data type description model.

Take following steps to get access to the OPC UA data type dictionary provider:

  1. Get the IEasyUAClientComplexData Interface service from your EasyUAClient Class instance using the GetService Method.
  2. Using the DataTypeDefinitionProvider Property, obtain the IUADataTypeDefinitionProvider Interface.

When you have the IUADataTypeDefinitionProvider Interface, you can call its methods to:

If you have more pieces of information to work on in the same way, it is much more efficient to process them together, in one operation. All methods on the IUADataTypeDictionaryProvider Interface therefore accept a read-only list on input, and return an array of processed element on the output. If performance is not a concern, or if you have just one piece of information to work on at a time, there are extension methods in the IUADataTypeDefinitionProviderExtension Class to make it easier as well.

Resolving the data type

When you receive complex data in the GenericData Property of a UAGenericObject, it has its DataType Property filled in with information about the associated data type, so that you can process it as you need. But what you have not yet received the complex data from the server - maybe you are just preparing something to be written, and you want to inspect what is the data type structure for certain node or data type ID? In this case, you can use the methods on the IUADataTypeModelProvider Interface to obtain an instance of DataType Class.

The example below shows how to resolve a data type. The main work is done by the ResolveDataType Method.

// Shows how to obtain object describing the data type of complex data node with OPC UA Complex Data plug-in.

using System;
using Microsoft.Extensions.DependencyInjection;
using OpcLabs.BaseLib.DataTypeModel;
using OpcLabs.BaseLib.OperationModel.Generic;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.AddressSpace;
using OpcLabs.EasyOpc.UA.AddressSpace.Standard;
using OpcLabs.EasyOpc.UA.InformationModel;
using OpcLabs.EasyOpc.UA.Plugins.ComplexData;

namespace UADocExamples.ComplexData._IEasyUAClientComplexData
{
    class ResolveDataType
    {
        public static void Main1()
        {
            // Define which server we will work with.
            UAEndpointDescriptor endpointDescriptor =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (not in .NET Standard)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            // Instantiate the client object.
            var client = new EasyUAClient();

            // Obtain the data type ID.
            //
            // In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
            // attribute, or easier, by calling the extension method ReadDataType on the IEasyUAClient interface.
            // The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract
            // data type, and the actual values are then sub-types of this base data type. This abstract data type does not
            // have any encodings associated with it and it is therefore not possible to extract its description from the
            // server. We therefore use a hard-coded data type ID for one of the sub-types in this example.
            //
            // The code to obtain the data type ID for given node would normally look like this:
            //    UANodeId dataTypeId = client.ReadDataType(
            //        endpointDescriptor,
            //        "nsu=http://test.org/UA/Data/ ;i=10239");    // [ObjectsFolder]/Data.Static.Scalar.StructureValue
            //
            UANodeId dataTypeId = "nsu=http://test.org/UA/Data/ ;i=9440";    // ScalarValueDataType

            // Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data 
            // operations.
            IEasyUAClientComplexData complexData = client.GetService<IEasyUAClientComplexData>();
            
            // Resolve the data type ID to the data type object, containing description of the data type.
            ValueResult<DataType> dataTypeResult = complexData.ResolveDataType(
                new UAModelNodeDescriptor(endpointDescriptor, dataTypeId), 
                UABrowseNames.DefaultBinary);
            // Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            if (!dataTypeResult.Succeeded)
            {
                Console.WriteLine("*** Failure: {0}", dataTypeResult.ErrorMessageBrief);
                return;
            }

            // The actual data type is in the Value property.
            // Display basic information about what we have obtained.
            Console.WriteLine(dataTypeResult.Value);

            // If we want to see the whole hierarchy of the received data type, we can format it with the "V" (verbose)
            // specifier. In the debugger, you can view the same by displaying the private DebugView property.
            Console.WriteLine();
            Console.WriteLine("{0:V}", dataTypeResult.Value);

            // For processing the internals of the data type, refer to examples for GenericData class.


            // Example output (truncated):
            //
            //ScalarValueDataType = structured
            //
            //ScalarValueDataType = structured
            //  [BooleanValue] Boolean = primitive(System.Boolean)
            //  [ByteStringValue] ByteString = primitive(System.Byte[])
            //  [ByteValue] Byte = primitive(System.Byte)
            //  [DateTimeValue] DateTime = primitive(System.DateTime)
            //  [DoubleValue] Double = primitive(System.Double)
            //  [EnumerationValue] Int32 = primitive(System.Int32)
            //  [ExpandedNodeIdValue] ExpandedNodeId = structured
            //    [ByteString] optional ByteStringNodeId = structured
            //      [Identifier] ByteString = primitive(System.Byte[])
            //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            //    [FourByte] optional FourByteNodeId = structured
            //      [Identifier] UInt16 = primitive(System.UInt16)
            //      [NamespaceIndex] Byte = primitive(System.Byte)
            //    [Guid] optional GuidNodeId = structured
            //      [Identifier] Guid = primitive(System.Guid)
            //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            //    [NamespaceURI] optional CharArray = primitive(System.String)
            //    [NamespaceURISpecified] switch Bit = primitive(System.Boolean)
            //    [NodeIdType] switch NodeIdType = enumeration(6)
            //      TwoByte = 0
            //      FourByte = 1
            //      Numeric = 2
            //      String = 3
            //      Guid = 4
            //      ByteString = 5
            //    [Numeric] optional NumericNodeId = structured
            //      [Identifier] UInt32 = primitive(System.UInt32)
            //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            //    [ServerIndex] optional UInt32 = primitive(System.UInt32)
            //    [ServerIndexSpecified] switch Bit = primitive(System.Boolean)
            //    [String] optional StringNodeId = structured
            //      [Identifier] CharArray = primitive(System.String)
            //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            //    [TwoByte] optional TwoByteNodeId = structured
            //      [Identifier] Byte = primitive(System.Byte)
            //  [FloatValue] Float = primitive(System.Single)
            //  [GuidValue] Guid = primitive(System.Guid)
            //  [Int16Value] Int16 = primitive(System.Int16)
            //  [Int32Value] Int32 = primitive(System.Int32)
            //  [Int64Value] Int64 = primitive(System.Int64)
            //  [Integer] Variant = structured
            //    [ArrayDimensions] optional sequence[*] of Int32 = primitive(System.Int32)
            //    [ArrayDimensionsSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
            //    [ArrayLength] length optional Int32 = primitive(System.Int32)
            //    [ArrayLengthSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
            //    [Boolean] optional sequence[*] of Boolean = primitive(System.Boolean)
            //    [Byte] optional sequence[*] of Byte = primitive(System.Byte)
        }
    }
}
// Shows how to obtain object describing the data type of complex data node with OPC UA Complex Data plug-in.

class procedure ResolveDataType.Main;
var
  Client: _EasyUAClient;
  ComplexData: _EasyUAClientComplexData;
  DataType: _DataType;
  DataTypeId: string;
  DataTypeResult: _ValueResult;
  EncodingName: _UAQualifiedName;
  EndpointDescriptor: string;
  ModelNodeDescriptor: _UAModelNodeDescriptor;
begin
  // Define which server and node we will work with.
  EndpointDescriptor :=
    'http://opcua.demo-this.com:51211/UA/SampleServer';
    //or 'https://opcua.demo-this.com:51212/UA/SampleServer/';
    //or 'opc.tcp://opcua.demo-this.com:51210/UA/SampleServer';

  // Instantiate the client object
  Client := CoEasyUAClient.Create;

  // Obtain the data type ID.
  //
  // In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
  // attribute.
  // The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract data type, and
  // the actual values are then sub-types of this base data type. This abstract data type does not have any encodings
  // associated with it and it is therefore not possible to extract its description from the server. We therefore use
  // a hard-coded data type ID for one of the sub-types in this example.
  DataTypeId := 'nsu=http://test.org/UA/Data/ ;i=9440';    // ScalarValueDataType

  // Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data
  // operations.
  ComplexData := IInterface(Client.GetServiceByName('OpcLabs.EasyOpc.UA.Plugins.ComplexData.IEasyUAClientComplexData, OpcLabs.EasyOpcUA')) as _EasyUAClientComplexData;

  // Resolve the data type ID to the data type object, containing description of the data type.
  ModelNodeDescriptor := CoUAModelNodeDescriptor.Create;
  ModelNodeDescriptor.EndpointDescriptor.UrlString := EndpointDescriptor;
  ModelNodeDescriptor.NodeDescriptor.NodeId.ExpandedText := DataTypeId;
  EncodingName := CoUAQualifiedName.Create;
  EncodingName.StandardName := 'DefaultBinary';
  DataTypeResult := ComplexData.ResolveDataType(ModelNodeDescriptor, EncodingName);
  if not DataTypeResult.Succeeded then
  begin
    WriteLn(Format('*** Failure: %s', [DataTypeResult.ErrorMessageBrief]));
    Exit;
  end;

  // The actual data type is in the Value property.
  DataType := IUnknown(DataTypeResult.Value) as _DataType;

  // Display basic information about what we have obtained.
  WriteLn(DataType.ToString);

  // If we want to see the whole hierarchy of the received data type, we can format it with the "V" (verbose)
  // specifier.
  Writeln;
  Writeln(DataType.ToString_2['V', nil]);

  // For processing the internals of the data type, refer to examples for GenericData class.


  // Example output (truncated):
  //
  //ScalarValueDataType = structured
  //
  //ScalarValueDataType = structured
  //  [BooleanValue] Boolean = primitive(System.Boolean)
  //  [ByteStringValue] ByteString = primitive(System.Byte[])
  //  [ByteValue] Byte = primitive(System.Byte)
  //  [DateTimeValue] DateTime = primitive(System.DateTime)
  //  [DoubleValue] Double = primitive(System.Double)
  //  [EnumerationValue] Int32 = primitive(System.Int32)
  //  [ExpandedNodeIdValue] ExpandedNodeId = structured
  //    [ByteString] optional ByteStringNodeId = structured
  //      [Identifier] ByteString = primitive(System.Byte[])
  //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
  //    [FourByte] optional FourByteNodeId = structured
  //      [Identifier] UInt16 = primitive(System.UInt16)
  //      [NamespaceIndex] Byte = primitive(System.Byte)
  //    [Guid] optional GuidNodeId = structured
  //      [Identifier] Guid = primitive(System.Guid)
  //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
  //    [NamespaceURI] optional CharArray = primitive(System.String)
  //    [NamespaceURISpecified] switch Bit = primitive(System.Boolean)
  //    [NodeIdType] switch NodeIdType = enumeration(6)
  //      TwoByte = 0
  //      FourByte = 1
  //      Numeric = 2
  //      String = 3
  //      Guid = 4
  //      ByteString = 5
  //    [Numeric] optional NumericNodeId = structured
  //      [Identifier] UInt32 = primitive(System.UInt32)
  //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
  //    [ServerIndex] optional UInt32 = primitive(System.UInt32)
  //    [ServerIndexSpecified] switch Bit = primitive(System.Boolean)
  //    [String] optional StringNodeId = structured
  //      [Identifier] CharArray = primitive(System.String)
  //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
  //    [TwoByte] optional TwoByteNodeId = structured
  //      [Identifier] Byte = primitive(System.Byte)
  //  [FloatValue] Float = primitive(System.Single)
  //  [GuidValue] Guid = primitive(System.Guid)
  //  [Int16Value] Int16 = primitive(System.Int16)
  //  [Int32Value] Int32 = primitive(System.Int32)
  //  [Int64Value] Int64 = primitive(System.Int64)
  //  [Integer] Variant = structured
  //    [ArrayDimensions] optional sequence[*] of Int32 = primitive(System.Int32)
  //    [ArrayDimensionsSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
  //    [ArrayLength] length optional Int32 = primitive(System.Int32)
  //    [ArrayLengthSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
  //    [Boolean] optional sequence[*] of Boolean = primitive(System.Boolean)
  //    [Byte] optional sequence[*] of Byte = primitive(System.Byte)

end;
' Shows how to obtain object describing the data type of complex data node with OPC UA Complex Data plug-in.

Imports System
Imports Microsoft.Extensions.DependencyInjection
Imports OpcLabs.BaseLib.DataTypeModel
Imports OpcLabs.BaseLib.OperationModel.Generic
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.AddressSpace
Imports OpcLabs.EasyOpc.UA.AddressSpace.Standard
Imports OpcLabs.EasyOpc.UA.InformationModel
Imports OpcLabs.EasyOpc.UA.Plugins.ComplexData

Namespace UADocExamples.ComplexData._IEasyUAClientComplexData

    Friend Class ResolveDataType

        Public Shared Sub Main1()

            ' Define which server we will work with.
            Dim endpointDescriptor As UAEndpointDescriptor =
                    "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"
            ' or "http://opcua.demo-this.com:51211/UA/SampleServer" (not in .NET Standard)
            ' or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            ' Instantiate the client object.
            Dim client = New EasyUAClient

            ' Obtain the data type ID.
            '
            ' In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
            ' attribute, or easier, by calling the extension method ReadDataType on the IEasyUAClient interface. The sample
            ' server, however, shows a more advanced approach in which the data type ID refers to an abstract data type,
            ' and the actual values are then sub-types of this base data type. This abstract data type does not have any
            ' encodings associated with it and it is therefore not possible to extract its description from the server.
            ' We therefore use a hard-coded data type ID for one of the sub-types in this example.
            '
            ' The code to obtain the data type ID for given node would normally look like this:
            '    UANodeId dataTypeId = client.ReadDataType(
            '        endpointDescriptor,
            '        "nsu=http://test.org/UA/Data/ ;i=10239");    // [ObjectsFolder]/Data.Static.Scalar.StructureValue
            '
            Dim dataTypeId As UANodeId = "nsu=http://test.org/UA/Data/ ;i=9440"  ' ScalarValueDataType

            ' Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data 
            ' operations.
            Dim complexData As IEasyUAClientComplexData = client.GetService(Of IEasyUAClientComplexData)()

            ' Resolve the data type ID to the data type object, containing description of the data type.
            Dim dataTypeResult As ValueResult(Of DataType) = complexData.ResolveDataType( _
                New UAModelNodeDescriptor(endpointDescriptor, dataTypeId), _
                UABrowseNames.DefaultBinary)
            ' Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            If Not dataTypeResult.Succeeded Then
                Console.WriteLine("*** Failure: {0}", dataTypeResult.ErrorMessageBrief)
                Exit Sub
            End If

            ' The actual data type is in the Value property.
            ' Display basic information about what we have obtained.
            Console.WriteLine(dataTypeResult.Value)

            ' If we want to see the whole hierarchy of the received data type, we can format it with the "V" (verbose)
            ' specifier. In the debugger, you can view the same by displaying the private DebugView property.
            Console.WriteLine()
            Console.WriteLine("{0:V}", dataTypeResult.Value)

            ' For processing the internals of the data type, refer to examples for GenericData class.


            ' Example output (truncated):
            '
            'ScalarValueDataType = structured
            '
            'ScalarValueDataType = structured
            '  [BooleanValue] Boolean = primitive(System.Boolean)
            '  [ByteStringValue] ByteString = primitive(System.Byte[])
            '  [ByteValue] Byte = primitive(System.Byte)
            '  [DateTimeValue] DateTime = primitive(System.DateTime)
            '  [DoubleValue] Double = primitive(System.Double)
            '  [EnumerationValue] Int32 = primitive(System.Int32)
            '  [ExpandedNodeIdValue] ExpandedNodeId = structured
            '    [ByteString] optional ByteStringNodeId = structured
            '      [Identifier] ByteString = primitive(System.Byte[])
            '      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            '    [FourByte] optional FourByteNodeId = structured
            '      [Identifier] UInt16 = primitive(System.UInt16)
            '      [NamespaceIndex] Byte = primitive(System.Byte)
            '    [Guid] optional GuidNodeId = structured
            '      [Identifier] Guid = primitive(System.Guid)
            '      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            '    [NamespaceURI] optional CharArray = primitive(System.String)
            '    [NamespaceURISpecified] switch Bit = primitive(System.Boolean)
            '    [NodeIdType] switch NodeIdType = enumeration(6)
            '      TwoByte = 0
            '      FourByte = 1
            '      Numeric = 2
            '      String = 3
            '      Guid = 4
            '      ByteString = 5
            '    [Numeric] optional NumericNodeId = structured
            '      [Identifier] UInt32 = primitive(System.UInt32)
            '      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            '    [ServerIndex] optional UInt32 = primitive(System.UInt32)
            '    [ServerIndexSpecified] switch Bit = primitive(System.Boolean)
            '    [String] optional StringNodeId = structured
            '      [Identifier] CharArray = primitive(System.String)
            '      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            '    [TwoByte] optional TwoByteNodeId = structured
            '      [Identifier] Byte = primitive(System.Byte)
            '  [FloatValue] Float = primitive(System.Single)
            '  [GuidValue] Guid = primitive(System.Guid)
            '  [Int16Value] Int16 = primitive(System.Int16)
            '  [Int32Value] Int32 = primitive(System.Int32)
            '  [Int64Value] Int64 = primitive(System.Int64)
            '  [Integer] Variant = structured
            '    [ArrayDimensions] optional sequence[*] of Int32 = primitive(System.Int32)
            '    [ArrayDimensionsSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
            '    [ArrayLength] length optional Int32 = primitive(System.Int32)
            '    [ArrayLengthSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
            '    [Boolean] optional sequence[*] of Boolean = primitive(System.Boolean)
            '    [Byte] optional sequence[*] of Byte = primitive(System.Byte)
        End Sub
    End Class
End Namespace
Rem Shows how to obtain object describing the data type of complex data node with OPC UA Complex Data plug-in.

Option Explicit

' Define which server we will work with.
Dim endpointDescriptor: endpointDescriptor = _
    "http://opcua.demo-this.com:51211/UA/SampleServer"  
'or "https://opcua.demo-this.com:51212/UA/SampleServer/"
'or "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"

' Instantiate the client object.
Dim Client: Set Client = CreateObject("OpcLabs.EasyOpc.UA.EasyUAClient")

' Obtain the data type ID.
'
' In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
' attribute. 
' The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract data type, and 
' the actual values are then sub-types of this base data type. This abstract data type does not have any encodings 
' associated with it and it is therefore not possible to extract its description from the server. We therefore use 
' a hard-coded data type ID for one of the sub-types in this example.
Dim dataTypeId: dataTypeId = "nsu=http://test.org/UA/Data/ ;i=9440"    ' ScalarValueDataType

' Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data 
' operations.
Dim ComplexData: Set ComplexData = _
    Client.GetServiceByName("OpcLabs.EasyOpc.UA.Plugins.ComplexData.IEasyUAClientComplexData, OpcLabs.EasyOpcUA")

' Resolve the data type ID to the data type object, containing description of the data type.
Dim ModelNodeDescriptor: Set ModelNodeDescriptor = CreateObject("OpcLabs.EasyOpc.UA.InformationModel.UAModelNodeDescriptor")
ModelNodeDescriptor.EndpointDescriptor.UrlString = endpointDescriptor
ModelNodeDescriptor.NodeDescriptor.NodeId.ExpandedText = dataTypeId
Dim EncodingName: Set EncodingName = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UAQualifiedName")
EncodingName.StandardName = "DefaultBinary"
Dim DataTypeResult: Set DataTypeResult = ComplexData.ResolveDataType(ModelNodeDescriptor, EncodingName)
If Not DataTypeResult.Succeeded Then
    WScript.Echo "*** Failure: "  & DataTypeResult.Exception.GetBaseException().Message
    WScript.Quit
End If

' The actual data type is in the Value property.
Dim DataType: Set DataType = DataTypeResult.Value

' Display basic information about what we have obtained.
WScript.Echo DataType

' If we want to see the whole hierarchy of the received data type, we can format it with the "V" (verbose)
' specifier. 
WScript.Echo
WScript.Echo DataType.ToString_2("V", Nothing)

' For processing the internals of the data type, refer to examples for GenericData class.


' Example output (truncated):
'
'ScalarValueDataType = structured
'
'ScalarValueDataType = structured
'  [BooleanValue] Boolean = primitive(System.Boolean)
'  [ByteStringValue] ByteString = primitive(System.Byte[])
'  [ByteValue] Byte = primitive(System.Byte)
'  [DateTimeValue] DateTime = primitive(System.DateTime)
'  [DoubleValue] Double = primitive(System.Double)
'  [EnumerationValue] Int32 = primitive(System.Int32)
'  [ExpandedNodeIdValue] ExpandedNodeId = structured
'    [ByteString] optional ByteStringNodeId = structured
'      [Identifier] ByteString = primitive(System.Byte[])
'      [NamespaceIndex] UInt16 = primitive(System.UInt16)
'    [FourByte] optional FourByteNodeId = structured
'      [Identifier] UInt16 = primitive(System.UInt16)
'      [NamespaceIndex] Byte = primitive(System.Byte)
'    [Guid] optional GuidNodeId = structured
'      [Identifier] Guid = primitive(System.Guid)
'      [NamespaceIndex] UInt16 = primitive(System.UInt16)
'    [NamespaceURI] optional CharArray = primitive(System.String)
'    [NamespaceURISpecified] switch Bit = primitive(System.Boolean)
'    [NodeIdType] switch NodeIdType = enumeration(6)
'      TwoByte = 0
'      FourByte = 1
'      Numeric = 2
'      String = 3
'      Guid = 4
'      ByteString = 5
'    [Numeric] optional NumericNodeId = structured
'      [Identifier] UInt32 = primitive(System.UInt32)
'      [NamespaceIndex] UInt16 = primitive(System.UInt16)
'    [ServerIndex] optional UInt32 = primitive(System.UInt32)
'    [ServerIndexSpecified] switch Bit = primitive(System.Boolean)
'    [String] optional StringNodeId = structured
'      [Identifier] CharArray = primitive(System.String)
'      [NamespaceIndex] UInt16 = primitive(System.UInt16)
'    [TwoByte] optional TwoByteNodeId = structured
'      [Identifier] Byte = primitive(System.Byte)
'  [FloatValue] Float = primitive(System.Single)
'  [GuidValue] Guid = primitive(System.Guid)
'  [Int16Value] Int16 = primitive(System.Int16)
'  [Int32Value] Int32 = primitive(System.Int32)
'  [Int64Value] Int64 = primitive(System.Int64)
'  [Integer] Variant = structured
'    [ArrayDimensions] optional sequence[*] of Int32 = primitive(System.Int32)
'    [ArrayDimensionsSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
'    [ArrayLength] length optional Int32 = primitive(System.Int32)
'    [ArrayLengthSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
'    [Boolean] optional sequence[*] of Boolean = primitive(System.Boolean)
'    [Byte] optional sequence[*] of Byte = primitive(System.Byte)

 

Obtaining content of the data type dictionary

You may sometimes need to view the actual content of the data type dictionary that resides in the OPC server. In itself, this is easy: The data type dictionary is in a node, so you just read the node. But, how do you find out which node to read? Here is where the IUADataTypeModelProvider Interface or the IUADataTypeDictionaryProvider Interface can help. They have methods to navigate from the node you want to access (read, write, or subscribe to) to the data type dictionary. Or, they have similar methods if you know the data type ID of the data type you are interested in. The example below shows the steps necessary.

// Shows how to obtain data type description object for complex data node with OPC UA Complex Data plug-in, and the actual
// content of the data type dictionary.

using System;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using OpcLabs.BaseLib.OperationModel.Generic;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.AddressSpace;
using OpcLabs.EasyOpc.UA.AddressSpace.Standard;
using OpcLabs.EasyOpc.UA.DataTypeModel;
using OpcLabs.EasyOpc.UA.DataTypeModel.Extensions;
using OpcLabs.EasyOpc.UA.InformationModel;
using OpcLabs.EasyOpc.UA.Plugins.ComplexData;

namespace UADocExamples.ComplexData._IUADataTypeDictionaryProvider
{
    class ResolveDataTypeDescriptorFromDataTypeEncodingId
    {
        public static void Main1()
        {
            // Define which server we will work with.
            UAEndpointDescriptor endpointDescriptor =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (not in .NET Standard)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            // Instantiate the client object.
            var client = new EasyUAClient();

            // Obtain the data type ID.
            //
            // In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
            // attribute, or easier, by calling the extension method ReadDataType on the IEasyUAClient interface. The sample
            // server, however, shows a more advanced approach in which the data type ID refers to an abstract data type,
            // and the actual values are then sub-types of this base data type. This abstract data type does not have any
            // encodings associated with it and it is therefore not possible to extract its description from the server.
            // We therefore use a hard-coded data type ID for one of the sub-types in this example.
            //
            // The code to obtain the data type ID for given node would normally look like this:
            //    UANodeId dataTypeId = client.ReadDataType(
            //        endpointUriString,
            //        "nsu=http://test.org/UA/Data/ ;i=10239");    // [ObjectsFolder]/Data.Static.Scalar.StructureValue
            //
            UANodeId dataTypeId = "nsu=http://test.org/UA/Data/ ;i=9440";    // ScalarValueDataType

            // Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data 
            // operations.
            IEasyUAClientComplexData complexData = client.GetService<IEasyUAClientComplexData>();

            // Get the data type model provider. Provides methods to access data types in OPC UA model.
            IUADataTypeModelProvider dataTypeModelProvider = complexData.DataTypeModelProvider;

            // Resolve the data type ID from our data type ID, for encoding name "Default Binary".
            ValueResult<UAModelNodeDescriptor> encodingIdResult = dataTypeModelProvider.ResolveEncodingIdFromDataTypeId(
                new UAModelNodeDescriptor(endpointDescriptor, dataTypeId),
                UABrowseNames.DefaultBinary);
            // Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            if (!encodingIdResult.Succeeded)
            {
                Console.WriteLine("*** Failure: {0}", encodingIdResult.ErrorMessageBrief);
                return;
            }
            UAModelNodeDescriptor encodingId = encodingIdResult.Value;

            // Get the data type dictionary provider. Provides methods to access data type dictionaries in OPC UA model.
            IUADataTypeDictionaryProvider dataTypeDictionaryProvider = complexData.DataTypeDictionaryProvider;

            // Resolve the data type descriptor from the encoding ID.
            ValueResult<UADataTypeDescriptor> dataTypeDescriptorResult =
                dataTypeDictionaryProvider.ResolveDataTypeDescriptorFromDataTypeEncodingId(encodingId);
            // Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            if (!dataTypeDescriptorResult.Succeeded)
            {
                Console.WriteLine("*** Failure: {0}", dataTypeDescriptorResult.ErrorMessageBrief);
                return;
            }
            UADataTypeDescriptor dataTypeDescriptor = dataTypeDescriptorResult.Value;

            // The data type descriptor contains two pieces of information:
            // The data type dictionary ID: This determines the dictionary where the data type is defined.
            Console.WriteLine(dataTypeDescriptor.DataTypeDictionaryId);
            // And the data type description: It is a "pointer" into the data type dictionary itself, selecting a specific 
            // type definition inside the data type dictionary. The format of it depends on the data type system;
            // in our case, it is a string that is the name of one of the type elements in the XML document of the data type
            // dictionary.
            Console.WriteLine(dataTypeDescriptor.DataTypeDescription);

            // Obtain the actual content of the data type dictionary.
            ValueResult<byte[]> dataTypeDictionaryResult =
                dataTypeDictionaryProvider.GetDataTypeDictionaryFromDataTypeDictionaryId(dataTypeDescriptor.DataTypeDictionaryId);
            // Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            if (!dataTypeDictionaryResult.Succeeded)
            {
                Console.WriteLine("*** Failure: {0}", dataTypeDictionaryResult.ErrorMessageBrief);
                return;
            }
            byte[] dataTypeDictionary = dataTypeDictionaryResult.Value;

            // The data type dictionary returned is an array of bytes; its syntax and semantics depends on the data type 
            // system. In our case, we know that the data type dictionary is actually a string encoded in UTF-8.
            string text = Encoding.UTF8.GetString(dataTypeDictionary);
            Console.WriteLine();
            Console.WriteLine(text);


            // Example output (truncated):
            //
            //http://opcua.demo-this.com:51211/UA/SampleServer; NodeId="nsu=http://test.org/UA/Data/ ;ns=2;i=11422"
            //ScalarValueDataType
            //
            //<opc:TypeDictionary
            //  xmlns:opc="http://opcfoundation.org/BinarySchema/"
            //  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            //  xmlns:ua="http://opcfoundation.org/UA/"
            //  xmlns:tns="http://test.org/UA/Data/"
            //  DefaultByteOrder="LittleEndian"
            //  TargetNamespace="http://test.org/UA/Data/"
            //>
            //  <!-- This File was generated on 2013-01-22 and supports the specifications supported by version 1.1.334.0 of the OPC UA deliverables. -->
            //  <opc:Import Namespace="http://opcfoundation.org/UA/" Location="Opc.Ua.BinarySchema.bsd"/>
            //
            //  <opc:StructuredType Name="ScalarValueDataType" BaseType="ua:ExtensionObject">
            //    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" />
            //    <opc:Field Name="SByteValue" TypeName="opc:SByte" />
            //    <opc:Field Name="ByteValue" TypeName="opc:Byte" />
            //    <opc:Field Name="Int16Value" TypeName="opc:Int16" />
            //    <opc:Field Name="UInt16Value" TypeName="opc:UInt16" />
            //    <opc:Field Name="Int32Value" TypeName="opc:Int32" />
            //    <opc:Field Name="UInt32Value" TypeName="opc:UInt32" />
            //    <opc:Field Name="Int64Value" TypeName="opc:Int64" />
            //    <opc:Field Name="UInt64Value" TypeName="opc:UInt64" />
            //    <opc:Field Name="FloatValue" TypeName="opc:Float" />
            //    <opc:Field Name="DoubleValue" TypeName="opc:Double" />
            //    <opc:Field Name="StringValue" TypeName="opc:String" />
            //    <opc:Field Name="DateTimeValue" TypeName="opc:DateTime" />
            //    <opc:Field Name="GuidValue" TypeName="opc:Guid" />
            //    <opc:Field Name="ByteStringValue" TypeName="opc:ByteString" />
            //    <opc:Field Name="XmlElementValue" TypeName="ua:XmlElement" />
            //    <opc:Field Name="NodeIdValue" TypeName="ua:NodeId" />
            //    <opc:Field Name="ExpandedNodeIdValue" TypeName="ua:ExpandedNodeId" />
            //    <opc:Field Name="QualifiedNameValue" TypeName="ua:QualifiedName" />
            //    <opc:Field Name="LocalizedTextValue" TypeName="ua:LocalizedText" />
            //    <opc:Field Name="StatusCodeValue" TypeName="ua:StatusCode" />
            //    <opc:Field Name="VariantValue" TypeName="ua:Variant" />
            //    <opc:Field Name="EnumerationValue" TypeName="ua:Int32" />
            //    <opc:Field Name="StructureValue" TypeName="ua:ExtensionObject" />
            //    <opc:Field Name="Number" TypeName="ua:Variant" />
            //    <opc:Field Name="Integer" TypeName="ua:Variant" />
            //    <opc:Field Name="UInteger" TypeName="ua:Variant" />
            //  </opc:StructuredType>
            //
            //  <opc:StructuredType Name="ArrayValueDataType" BaseType="ua:ExtensionObject">
            //    <opc:Field Name="NoOfBooleanValue" TypeName="opc:Int32" />
            //    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" LengthField="NoOfBooleanValue" />
            //    <opc:Field Name="NoOfSByteValue" TypeName="opc:Int32" />
        }
    }
}
// Shows how to obtain data type description object for complex data node with OPC UA Complex Data plug-in, and the actual
// content of the data type dictionary.

class procedure ResolveDataTypeDescriptorFromDataTypeEncodingId.Main;
var
  Client: _EasyUAClient;
  ComplexData: _EasyUAClientComplexData;
  DataTypeDictionary: OleVariant;
  DataTypeDictionaryResult: _ValueResult;
  DataTypeDescriptor: _UADataTypeDescriptor;
  DataTypeDescriptorResult: _ValueResult;
  DataTypeId: string;
  DataTypeModelProvider: _UADataTypeModelProvider;
  DataTypeDictionaryProvider: _UADataTypeDictionaryProvider;
  EncodingId: _UAModelNodeDescriptor;
  EncodingIdResult: _ValueResult;
  EncodingName: _UAQualifiedName;
  EndpointDescriptor: string;
  I: Cardinal;
  ModelNodeDescriptor: _UAModelNodeDescriptor;
  Text: string;
begin
  // Define which server and node we will work with.
  EndpointDescriptor :=
    'http://opcua.demo-this.com:51211/UA/SampleServer';
    //or 'https://opcua.demo-this.com:51212/UA/SampleServer/';
    //or 'opc.tcp://opcua.demo-this.com:51210/UA/SampleServer';

  // Instantiate the client object
  Client := CoEasyUAClient.Create;

  // Obtain the data type ID.
  //
  // In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
  // attribute.
  // The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract data type, and
  // the actual values are then sub-types of this base data type. This abstract data type does not have any encodings
  // associated with it and it is therefore not possible to extract its description from the server. We therefore use
  // a hard-coded data type ID for one of the sub-types in this example.
  DataTypeId := 'nsu=http://test.org/UA/Data/ ;i=9440';    // ScalarValueDataType

  // Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data
  // operations.
  ComplexData := IInterface(Client.GetServiceByName('OpcLabs.EasyOpc.UA.Plugins.ComplexData.IEasyUAClientComplexData, OpcLabs.EasyOpcUA')) as _EasyUAClientComplexData;

  // Get the data type model provider. Provides methods to access data types in OPC UA model.
  DataTypeModelProvider := ComplexData.DataTypeModelProvider;

  // Resolve the data type ID from our data type ID, for encoding name "Default Binary".
  ModelNodeDescriptor := CoUAModelNodeDescriptor.Create;
  ModelNodeDescriptor.EndpointDescriptor.UrlString := EndpointDescriptor;
  ModelNodeDescriptor.NodeDescriptor.NodeId.ExpandedText := DataTypeId;
  EncodingName := CoUAQualifiedName.Create;
  EncodingName.StandardName := 'DefaultBinary';
  EncodingIdResult := DataTypeModelProvider.ResolveEncodingIdFromDataTypeId(ModelNodeDescriptor, EncodingName);
  // Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
  if not EncodingIdResult.Succeeded then
  begin
    WriteLn(Format('*** Failure: %s', [EncodingIdResult.ErrorMessageBrief]));
    Exit;
  end;
  EncodingId := IUnknown(EncodingIdResult.Value) as _UAModelNodeDescriptor;

  // Get the data type dictionary provider. Provides methods to access data type dictionaries in OPC UA model.
  DataTypeDictionaryProvider := ComplexData.DataTypeDictionaryProvider;

  // Resolve the data type descriptor from the encoding ID.
  DataTypeDescriptorResult := DataTypeDictionaryProvider.ResolveDataTypeDescriptorFromDataTypeEncodingId(EncodingId);
  // Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
  if not DataTypeDescriptorResult.Succeeded then
  begin
    WriteLn(Format('*** Failure: %s', [DataTypeDescriptorResult.ErrorMessageBrief]));
    Exit;
  end;
  DataTypeDescriptor := IUnknown(DataTypeDescriptorResult.Value) as _UADataTypeDescriptor;

  // The data type descriptor contains two pieces of information:
  // The data type dictionary ID: This determines the dictionary where the data type is defined.
  WriteLn(DataTypeDescriptor.DataTypeDictionaryId.ToString);
  // And the data type description: It is a "pointer" into the data type dictionary itself, selecting a specific
  // type definition inside the data type dictionary. The format of it depends on the data type system;
  // in our case, it is a string that is the name of one of the type elements in the XML document of the data type
  // dictionary.
  WriteLn(DataTypeDescriptor.DataTypeDescription);

  // Obtain the actual content of the data type dictionary.
  DataTypeDictionaryResult :=
    DataTypeDictionaryProvider.GetDataTypeDictionaryFromDataTypeDictionaryId(DataTypeDescriptor.DataTypeDictionaryId);
  // Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
  if not DataTypeDictionaryResult.Succeeded then
  begin
    WriteLn(Format('*** Failure: %s', [DataTypeDictionaryResult.ErrorMessageBrief]));
    Exit;
  end;
  DataTypeDictionary := DataTypeDictionaryResult.Value;

  // The data type dictionary returned is an array of bytes; its syntax and semantics depends on the data type
  // system. In our case, we know that the data type dictionary is actually a string encoded in UTF-8.
  for I := VarArrayLowBound(DataTypeDictionary, 1) to VarArrayHighBound(DataTypeDictionary, 1) do
  begin
      Text := Text + Chr(Byte(DataTypeDictionary[I]));
  end;

  WriteLn;
  WriteLn(Text);

  // Example output (truncated):
  //
  //http://opcua.demo-this.com:51211/UA/SampleServer; NodeId="nsu=http://test.org/UA/Data/ ;ns=2;i=11422"
  //ScalarValueDataType
  //
  //<opc:TypeDictionary
  //  xmlns:opc="http://opcfoundation.org/BinarySchema/"
  //  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  //  xmlns:ua="http://opcfoundation.org/UA/"
  //  xmlns:tns="http://test.org/UA/Data/"
  //  DefaultByteOrder="LittleEndian"
  //  TargetNamespace="http://test.org/UA/Data/"
  //>
  //  <!-- This File was generated on 2013-01-22 and supports the specifications supported by version 1.1.334.0 of the OPC UA deliverables. -->
  //  <opc:Import Namespace="http://opcfoundation.org/UA/" Location="Opc.Ua.BinarySchema.bsd"/>
  //
  //  <opc:StructuredType Name="ScalarValueDataType" BaseType="ua:ExtensionObject">
  //    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" />
  //    <opc:Field Name="SByteValue" TypeName="opc:SByte" />
  //    <opc:Field Name="ByteValue" TypeName="opc:Byte" />
  //    <opc:Field Name="Int16Value" TypeName="opc:Int16" />
  //    <opc:Field Name="UInt16Value" TypeName="opc:UInt16" />
  //    <opc:Field Name="Int32Value" TypeName="opc:Int32" />
  //    <opc:Field Name="UInt32Value" TypeName="opc:UInt32" />
  //    <opc:Field Name="Int64Value" TypeName="opc:Int64" />
  //    <opc:Field Name="UInt64Value" TypeName="opc:UInt64" />
  //    <opc:Field Name="FloatValue" TypeName="opc:Float" />
  //    <opc:Field Name="DoubleValue" TypeName="opc:Double" />
  //    <opc:Field Name="StringValue" TypeName="opc:String" />
  //    <opc:Field Name="DateTimeValue" TypeName="opc:DateTime" />
  //    <opc:Field Name="GuidValue" TypeName="opc:Guid" />
  //    <opc:Field Name="ByteStringValue" TypeName="opc:ByteString" />
  //    <opc:Field Name="XmlElementValue" TypeName="ua:XmlElement" />
  //    <opc:Field Name="NodeIdValue" TypeName="ua:NodeId" />
  //    <opc:Field Name="ExpandedNodeIdValue" TypeName="ua:ExpandedNodeId" />
  //    <opc:Field Name="QualifiedNameValue" TypeName="ua:QualifiedName" />
  //    <opc:Field Name="LocalizedTextValue" TypeName="ua:LocalizedText" />
  //    <opc:Field Name="StatusCodeValue" TypeName="ua:StatusCode" />
  //    <opc:Field Name="VariantValue" TypeName="ua:Variant" />
  //    <opc:Field Name="EnumerationValue" TypeName="ua:Int32" />
  //    <opc:Field Name="StructureValue" TypeName="ua:ExtensionObject" />
  //    <opc:Field Name="Number" TypeName="ua:Variant" />
  //    <opc:Field Name="Integer" TypeName="ua:Variant" />
  //    <opc:Field Name="UInteger" TypeName="ua:Variant" />
  //  </opc:StructuredType>
  //
  //  <opc:StructuredType Name="ArrayValueDataType" BaseType="ua:ExtensionObject">
  //    <opc:Field Name="NoOfBooleanValue" TypeName="opc:Int32" />
  //    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" LengthField="NoOfBooleanValue" />
  //    <opc:Field Name="NoOfSByteValue" TypeName="opc:Int32" />

end;
' Shows how to obtain data type description object for complex data node with OPC UA Complex Data plug-in, and the actual
' content of the data type dictionary.

Imports System
Imports System.Text
Imports Microsoft.Extensions.DependencyInjection
Imports OpcLabs.BaseLib.OperationModel.Generic
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.AddressSpace
Imports OpcLabs.EasyOpc.UA.AddressSpace.Standard
Imports OpcLabs.EasyOpc.UA.DataTypeModel
Imports OpcLabs.EasyOpc.UA.DataTypeModel.Extensions
Imports OpcLabs.EasyOpc.UA.InformationModel
Imports OpcLabs.EasyOpc.UA.Plugins.ComplexData

Namespace UADocExamples.ComplexData._IUADataTypeDictionaryProvider

    Friend Class ResolveDataTypeDescriptorFromDataTypeEncodingId

        Public Shared Sub Main1()

            ' Define which server we will work with.
            Dim endpointDescriptor As UAEndpointDescriptor =
                    "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"
            ' or "http://opcua.demo-this.com:51211/UA/SampleServer" (not in .NET Standard)
            ' or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            ' Instantiate the client object.
            Dim client = New EasyUAClient

            ' Obtain the data type ID.
            '
            ' In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
            ' attribute, or easier, by calling the extension method ReadDataType on the IEasyUAClient interface. The sample
            ' server, however, shows a more advanced approach in which the data type ID refers to an abstract data type,
            ' and the actual values are then sub-types of this base data type. This abstract data type does not have any
            ' encodings associated with it and it is therefore not possible to extract its description from the server.
            ' We therefore use a hard-coded data type ID for one of the sub-types in this example.
            '
            ' The code to obtain the data type ID for given node would normally look like this:
            '    UANodeId dataTypeId = client.ReadDataType(
            '        endpointUriString,
            '        "nsu=http://test.org/UA/Data/ ;i=10239");    // [ObjectsFolder]/Data.Static.Scalar.StructureValue
            '
            Dim dataTypeId As UANodeId = "nsu=http://test.org/UA/Data/ ;i=9440"  ' ScalarValueDataType

            ' Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data 
            ' operations.
            Dim complexData As IEasyUAClientComplexData = client.GetService(Of IEasyUAClientComplexData)()

            ' Get the data type model provider. Provides methods to access data types in OPC UA model.
            Dim dataTypeModelProvider As IUADataTypeModelProvider = complexData.DataTypeModelProvider

            ' Resolve the data type ID from our data type ID, for encoding name "Default Binary".
            Dim encodingIdResult As ValueResult(Of UAModelNodeDescriptor) = dataTypeModelProvider.ResolveEncodingIdFromDataTypeId(
                New UAModelNodeDescriptor(endpointDescriptor, dataTypeId),
                UABrowseNames.DefaultBinary)
            ' Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            If Not encodingIdResult.Succeeded Then
                Console.WriteLine("*** Failure: {0}", encodingIdResult.ErrorMessageBrief)
                Exit Sub
            End If
            Dim encodingId As UAModelNodeDescriptor = encodingIdResult.Value

            ' Get the data type dictionary provider. Provides methods to access data type dictionaries in OPC UA model.
            Dim dataTypeDictionaryProvider As IUADataTypeDictionaryProvider = complexData.DataTypeDictionaryProvider

            ' Resolve the data type descriptor from the encoding ID.
            Dim dataTypeDescriptorResult As ValueResult(Of UADataTypeDescriptor) =
                    dataTypeDictionaryProvider.ResolveDataTypeDescriptorFromDataTypeEncodingId(encodingId)
            ' Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            If Not dataTypeDescriptorResult.Succeeded Then
                Console.WriteLine("*** Failure: {0}", dataTypeDescriptorResult.ErrorMessageBrief)
                Exit Sub
            End If
            Dim dataTypeDescriptor As UADataTypeDescriptor = dataTypeDescriptorResult.Value

            ' The data type descriptor contains two pieces of information:
            ' The data type dictionary ID: This determines the dictionary where the data type is defined.
            Console.WriteLine(dataTypeDescriptor.DataTypeDictionaryId)
            ' And the data type description: It is a "pointer" into the data type dictionary itself, selecting a specific 
            ' type definition inside the data type dictionary. The format of it depends on the data type system;
            ' in our case, it is a string that is the name of one of the type elements in the XML document of the data type
            ' dictionary.
            Console.WriteLine(dataTypeDescriptor.DataTypeDescription)

            ' Obtain the actual content of the data type dictionary.
            Dim dataTypeDictionaryResult As ValueResult(Of Byte()) =
                    dataTypeDictionaryProvider.GetDataTypeDictionaryFromDataTypeDictionaryId(dataTypeDescriptor.DataTypeDictionaryId)
            ' Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            If Not dataTypeDictionaryResult.Succeeded Then
                Console.WriteLine("*** Failure: {0}", dataTypeDictionaryResult.ErrorMessageBrief)
                Exit Sub
            End If
            Dim dataTypeDictionary() As Byte = dataTypeDictionaryResult.Value

            ' The data type dictionary returned is an array of bytes; its syntax and semantics depends on the data type 
            ' system. In our case, we know that the data type dictionary is actually a string encoded in UTF-8.
            Dim text As String = Encoding.UTF8.GetString(dataTypeDictionary)
            Console.WriteLine()
            Console.WriteLine(text)


            ' Example output (truncated):
            '
            'http://opcua.demo-this.com:51211/UA/SampleServer; NodeId="nsu=http://test.org/UA/Data/ ;ns=2;i=11422"
            'ScalarValueDataType
            '
            '<opc:TypeDictionary
            '  xmlns:opc="http://opcfoundation.org/BinarySchema/"
            '  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            '  xmlns:ua="http://opcfoundation.org/UA/"
            '  xmlns:tns="http://test.org/UA/Data/"
            '  DefaultByteOrder="LittleEndian"
            '  TargetNamespace="http://test.org/UA/Data/"
            '>
            '  <!-- This File was generated on 2013-01-22 and supports the specifications supported by version 1.1.334.0 of the OPC UA deliverables. -->
            '  <opc:Import Namespace="http://opcfoundation.org/UA/" Location="Opc.Ua.BinarySchema.bsd"/>
            '
            '  <opc:StructuredType Name="ScalarValueDataType" BaseType="ua:ExtensionObject">
            '    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" />
            '    <opc:Field Name="SByteValue" TypeName="opc:SByte" />
            '    <opc:Field Name="ByteValue" TypeName="opc:Byte" />
            '    <opc:Field Name="Int16Value" TypeName="opc:Int16" />
            '    <opc:Field Name="UInt16Value" TypeName="opc:UInt16" />
            '    <opc:Field Name="Int32Value" TypeName="opc:Int32" />
            '    <opc:Field Name="UInt32Value" TypeName="opc:UInt32" />
            '    <opc:Field Name="Int64Value" TypeName="opc:Int64" />
            '    <opc:Field Name="UInt64Value" TypeName="opc:UInt64" />
            '    <opc:Field Name="FloatValue" TypeName="opc:Float" />
            '    <opc:Field Name="DoubleValue" TypeName="opc:Double" />
            '    <opc:Field Name="StringValue" TypeName="opc:String" />
            '    <opc:Field Name="DateTimeValue" TypeName="opc:DateTime" />
            '    <opc:Field Name="GuidValue" TypeName="opc:Guid" />
            '    <opc:Field Name="ByteStringValue" TypeName="opc:ByteString" />
            '    <opc:Field Name="XmlElementValue" TypeName="ua:XmlElement" />
            '    <opc:Field Name="NodeIdValue" TypeName="ua:NodeId" />
            '    <opc:Field Name="ExpandedNodeIdValue" TypeName="ua:ExpandedNodeId" />
            '    <opc:Field Name="QualifiedNameValue" TypeName="ua:QualifiedName" />
            '    <opc:Field Name="LocalizedTextValue" TypeName="ua:LocalizedText" />
            '    <opc:Field Name="StatusCodeValue" TypeName="ua:StatusCode" />
            '    <opc:Field Name="VariantValue" TypeName="ua:Variant" />
            '    <opc:Field Name="EnumerationValue" TypeName="ua:Int32" />
            '    <opc:Field Name="StructureValue" TypeName="ua:ExtensionObject" />
            '    <opc:Field Name="Number" TypeName="ua:Variant" />
            '    <opc:Field Name="Integer" TypeName="ua:Variant" />
            '    <opc:Field Name="UInteger" TypeName="ua:Variant" />
            '  </opc:StructuredType>
            '
            '  <opc:StructuredType Name="ArrayValueDataType" BaseType="ua:ExtensionObject">
            '    <opc:Field Name="NoOfBooleanValue" TypeName="opc:Int32" />
            '    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" LengthField="NoOfBooleanValue" />
            '    <opc:Field Name="NoOfSByteValue" TypeName="opc:Int32" />
        End Sub
    End Class
End Namespace
Rem Shows how to obtain data type description object for complex data node with OPC UA Complex Data plug-in, and the actual
Rem content of the data type dictionary.

Option Explicit

' Define which server we will work with.
Dim endpointDescriptor: endpointDescriptor = _
    "http://opcua.demo-this.com:51211/UA/SampleServer"  
'or "https://opcua.demo-this.com:51212/UA/SampleServer/"
'or "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"

' Instantiate the client object.
Dim Client: Set Client = CreateObject("OpcLabs.EasyOpc.UA.EasyUAClient")

' Obtain the data type ID.
'
' In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
' attribute. 
' The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract data type, and 
' the actual values are then sub-types of this base data type. This abstract data type does not have any encodings 
' associated with it and it is therefore not possible to extract its description from the server. We therefore use 
' a hard-coded data type ID for one of the sub-types in this example.
Dim dataTypeId: dataTypeId = "nsu=http://test.org/UA/Data/ ;i=9440"    ' ScalarValueDataType

' Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data 
' operations.
Dim ComplexData: Set ComplexData = _
    Client.GetServiceByName("OpcLabs.EasyOpc.UA.Plugins.ComplexData.IEasyUAClientComplexData, OpcLabs.EasyOpcUA")

' Get the data type model provider. Provides methods to access data types in OPC UA model.
Dim DataTypeModelProvider: Set DataTypeModelProvider = ComplexData.DataTypeModelProvider

' Resolve the data type ID from our data type ID, for encoding name "Default Binary".
Dim ModelNodeDescriptor: Set ModelNodeDescriptor = CreateObject("OpcLabs.EasyOpc.UA.InformationModel.UAModelNodeDescriptor")
ModelNodeDescriptor.EndpointDescriptor.UrlString = endpointDescriptor
ModelNodeDescriptor.NodeDescriptor.NodeId.ExpandedText = dataTypeId
Dim EncodingName: Set EncodingName = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UAQualifiedName")
EncodingName.StandardName = "DefaultBinary"
Dim EncodingIdResult: Set EncodingIdResult = _
    DataTypeModelProvider.ResolveEncodingIdFromDataTypeId(ModelNodeDescriptor, EncodingName)
' Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
If Not EncodingIdResult.Succeeded Then
    WScript.Echo "*** Failure: "  & EncodingIdResult.Exception.GetBaseException().Message
    WScript.Quit
End If
Dim EncodingId: Set EncodingId = EncodingIdResult.Value

' Get the data type dictionary provider. Provides methods to access data type dictionaries in OPC UA model.
Dim DataTypeDictionaryProvider: Set DataTypeDictionaryProvider = ComplexData.DataTypeDictionaryProvider

' Resolve the data type descriptor from the encoding ID.
Dim DataTypeDescriptorResult: Set DataTypeDescriptorResult = _
    DataTypeDictionaryProvider.ResolveDataTypeDescriptorFromDataTypeEncodingId(EncodingId)
' Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
If Not DataTypeDescriptorResult.Succeeded Then
    WScript.Echo "*** Failure: "  & DataTypeDescriptorResult.Exception.GetBaseException().Message
    WScript.Quit
End If
Dim DataTypeDescriptor: Set DataTypeDescriptor = DataTypeDescriptorResult.Value

' The data type descriptor contains two pieces of information:
' The data type dictionary ID: This determines the dictionary where the data type is defined.
WScript.Echo DataTypeDescriptor.DataTypeDictionaryId
' And the data type description: It is a "pointer" into the data type dictionary itself, selecting a specific 
' type definition inside the data type dictionary. The format of it depends on the data type system;
' in our case, it is a string that is the name of one of the type elements in the XML document of the data type
' dictionary.
WScript.Echo DataTypeDescriptor.DataTypeDescription

' Obtain the actual content of the data type dictionary.
Dim DataTypeDictionaryResult: Set DataTypeDictionaryResult = _
    DataTypeDictionaryProvider.GetDataTypeDictionaryFromDataTypeDictionaryId(DataTypeDescriptor.DataTypeDictionaryId)
' Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
If Not DataTypeDictionaryResult.Succeeded Then
    WScript.Echo "*** Failure: "  & DataTypeDictionaryResult.Exception.GetBaseException().Message
    WScript.Quit
End If
Dim DataTypeDictionary: DataTypeDictionary = DataTypeDictionaryResult.Value

' The data type dictionary returned is an array of bytes; its syntax and semantics depends on the data type 
' system. In our case, we know that the data type dictionary is actually a string encoded in UTF-8.
Dim text
Dim i: For i = LBound(DataTypeDictionary) To UBound(DataTypeDictionary)
    text = text & Chr(DataTypeDictionary(i))
Next
WScript.Echo
WScript.Echo text


' Example output (truncated):
'
'http://opcua.demo-this.com:51211/UA/SampleServer; NodeId="nsu=http:'test.org/UA/Data/;ns=2;i=11422"
'ScalarValueDataType
'
'<opc:TypeDictionary
'  xmlns:opc="http:'opcfoundation.org/BinarySchema/"
'  xmlns:xsi="http:'www.w3.org/2001/XMLSchema-instance"
'  xmlns:ua="http:'opcfoundation.org/UA/"
'  xmlns:tns="http:'test.org/UA/Data/"
'  DefaultByteOrder="LittleEndian"
'  TargetNamespace="http:'test.org/UA/Data/"
'>
'  <!-- This File was generated on 2013-01-22 and supports the specifications supported by version 1.1.334.0 of the OPC UA deliverables. -->
'  <opc:Import Namespace="http:'opcfoundation.org/UA/" Location="Opc.Ua.BinarySchema.bsd"/>
'
'  <opc:StructuredType Name="ScalarValueDataType" BaseType="ua:ExtensionObject">
'    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" />
'    <opc:Field Name="SByteValue" TypeName="opc:SByte" />
'    <opc:Field Name="ByteValue" TypeName="opc:Byte" />
'    <opc:Field Name="Int16Value" TypeName="opc:Int16" />
'    <opc:Field Name="UInt16Value" TypeName="opc:UInt16" />
'    <opc:Field Name="Int32Value" TypeName="opc:Int32" />
'    <opc:Field Name="UInt32Value" TypeName="opc:UInt32" />
'    <opc:Field Name="Int64Value" TypeName="opc:Int64" />
'    <opc:Field Name="UInt64Value" TypeName="opc:UInt64" />
'    <opc:Field Name="FloatValue" TypeName="opc:Float" />
'    <opc:Field Name="DoubleValue" TypeName="opc:Double" />
'    <opc:Field Name="StringValue" TypeName="opc:String" />
'    <opc:Field Name="DateTimeValue" TypeName="opc:DateTime" />
'    <opc:Field Name="GuidValue" TypeName="opc:Guid" />
'    <opc:Field Name="ByteStringValue" TypeName="opc:ByteString" />
'    <opc:Field Name="XmlElementValue" TypeName="ua:XmlElement" />
'    <opc:Field Name="NodeIdValue" TypeName="ua:NodeId" />
'    <opc:Field Name="ExpandedNodeIdValue" TypeName="ua:ExpandedNodeId" />
'    <opc:Field Name="QualifiedNameValue" TypeName="ua:QualifiedName" />
'    <opc:Field Name="LocalizedTextValue" TypeName="ua:LocalizedText" />
'    <opc:Field Name="StatusCodeValue" TypeName="ua:StatusCode" />
'    <opc:Field Name="VariantValue" TypeName="ua:Variant" />
'    <opc:Field Name="EnumerationValue" TypeName="ua:Int32" />
'    <opc:Field Name="StructureValue" TypeName="ua:ExtensionObject" />
'    <opc:Field Name="Number" TypeName="ua:Variant" />
'    <opc:Field Name="Integer" TypeName="ua:Variant" />
'    <opc:Field Name="UInteger" TypeName="ua:Variant" />
'  </opc:StructuredType>
'
'  <opc:StructuredType Name="ArrayValueDataType" BaseType="ua:ExtensionObject">
'    <opc:Field Name="NoOfBooleanValue" TypeName="opc:Int32" />
'    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" LengthField="NoOfBooleanValue" />
'    <opc:Field Name="NoOfSByteValue" TypeName="opc:Int32" />

 

 

See Also

Reference