QuickOPC User's Guide and Reference
DABrowseParameters Class
Members 



View with Navigation Tools
OpcLabs.EasyOpcClassic Assembly > OpcLabs.EasyOpc.DataAccess Namespace : DABrowseParameters Class
Contains filtering conditions for OPC Data Access node browsing.
Object Model
DABrowseParameters ClassDAAccessRight ClassVarType ClassDABrowseParameters ClassDAAccessRight ClassVarType ClassDABrowseParameters Class
Syntax
'Declaration
 
<CLSCompliantAttribute(True)>
<ComDefaultInterfaceAttribute(OpcLabs.EasyOpc.DataAccess.ComTypes._DABrowseParameters)>
<ComVisibleAttribute(True)>
<GuidAttribute("662D7CC7-E83C-462E-90B4-6B4351466A5A")>
<TypeConverterAttribute(System.ComponentModel.ExpandableObjectConverter)>
<ValueControlAttribute("OpcLabs.BaseLib.Forms.Common.ObjectSerializationControl, OpcLabs.BaseLibForms, Version=5.63.115.1, Culture=neutral, PublicKeyToken=6faddca41dacb409", 
   DefaultReadWrite=False, 
   Export=True, 
   PageId=10001)>
<SerializableAttribute()>
Public NotInheritable Class DABrowseParameters 
   Inherits OpcLabs.BaseLib.Parameters
   Implements LINQPad.ICustomMemberProvider, OpcLabs.BaseLib.ComTypes._Info, OpcLabs.BaseLib.ComTypes._Object2, OpcLabs.BaseLib.ComTypes._Parameters, OpcLabs.EasyOpc.DataAccess.ComTypes._DABrowseParameters, System.ICloneable, System.Runtime.Serialization.ISerializable, System.Xml.Serialization.IXmlSerializable 
 
'Usage
 
Dim instance As DABrowseParameters
Remarks

 

OPC Address Space Organization

Items in an OPC server are typically organized in a tree hierarchy (address space), where the branch nodes serve organizational purposes (similar to folders in a file system), while the leaf nodes correspond to actual pieces of data that can be accessed (similar to files in a file system) – the OPC items. Each node has a “short” name that is unique among other branches or leaves under the same parent branch (or a root). Leaf nodes can be fully identified using a “long” ItemID, which determines the OPC item without a need to further qualify it with its position in the tree. ItemIDs may look like “Device1.Block101.Setpoint”, however their syntax and meaning is fully determined by the particular OPC server they are coming from.

Browse Methods

QuickOPC gives you methods to traverse through the address space information and obtain the information available there. It is also possible to filter the returned nodes by various criteria, such as node name matching certain pattern, or a particular data type only, or writeable items only, etc.

If you want to retrieve a list of all sub-branches under a given branch (or under a root) of the OPC server, call the BrowseBranches method. You will receive back a DANodeElementCollection object. Each DANodeElement contains information gathered about one sub-branch node, such as its name, or indication whether it has children.

// This example shows how to obtain all branches at the root of the address space. For each branch, it displays whether 
// it may have child nodes.

using System;
using OpcLabs.EasyOpc.DataAccess;
using OpcLabs.EasyOpc.DataAccess.AddressSpace;
using OpcLabs.EasyOpc.OperationModel;

namespace DocExamples.DataAccess._EasyDAClient
{
    class BrowseBranches
    {
        public static void Main1()
        {
            // Instantiate the client object.
            var client = new EasyDAClient();
            DANodeElementCollection branchElements;
            try
            {
                branchElements = client.BrowseBranches("", "OPCLabs.KitServer.2", "");
            }
            catch (OpcException opcException)
            {
                Console.WriteLine("*** Failure: {0}", opcException.GetBaseException().Message);
                return;
            }

            foreach (DANodeElement branchElement in branchElements)
                Console.WriteLine($"BranchElements(\"{branchElement.Name}\").HasChildren: {branchElement.HasChildren}");
        }


        // Example output:
        //
        //BranchElements("$ServerControl").HasChildren: True
        //BranchElements("Boilers").HasChildren: True
        //BranchElements("Simulation").HasChildren: True
        //BranchElements("SimulateEvents").HasChildren: True
        //BranchElements("Trends").HasChildren: True
        //BranchElements("Demo").HasChildren: True
        //BranchElements("Greenhouse").HasChildren: True
    }
}

 

Similarly, if you want to retrieve a list of leaves under a given branch (or under a root) of the OPC server, call the BrowseLeaves method. You will also receive back a DANodeElementCollection object, this time containing the leaves only. You can find information such as the Item ID from the DANodeElement of any leaf, and pass it further to methods like ReadItem or SubscribeItem.

// This example shows how to obtain all leaves under the "Simulation" branch of the address space. For each leaf, it displays 
// the ItemID of the node.

using System;
using OpcLabs.EasyOpc.DataAccess;
using OpcLabs.EasyOpc.DataAccess.AddressSpace;
using OpcLabs.EasyOpc.OperationModel;

namespace DocExamples.DataAccess._EasyDAClient
{
    class BrowseLeaves
    {
        public static void Main1()
        {
            // Instantiate the client object.
            var client = new EasyDAClient();
            DANodeElementCollection leafElements;
            try
            {
                leafElements = client.BrowseLeaves("", "OPCLabs.KitServer.2", "Simulation");
            }
            catch (OpcException opcException)
            {
                Console.WriteLine("*** Failure: {0}", opcException.GetBaseException().Message);
                return;
            }

            foreach (DANodeElement leafElement in leafElements)
                Console.WriteLine($"LeafElements(\"{leafElement.Name}\").ItemId: {leafElement.ItemId}");
        }


        // Example output:
        //
        //LeafElements("Register_ArrayOfI2").ItemId: Simulation.Register_ArrayOfI2
        //LeafElements("Register_ArrayOfI4").ItemId: Simulation.Register_ArrayOfI4
        //LeafElements("Staircase 0:2 (10 s)").ItemId: Simulation.Staircase 0:2 (10 s)
        //LeafElements("Constant_VARIANT").ItemId: Simulation.Constant_VARIANT
        //LeafElements("Staircase 0:10 (1 s)").ItemId: Simulation.Staircase 0:10 (1 s)
        //LeafElements("Register_DATE").ItemId: Simulation.Register_DATE
        //LeafElements("Constant_RECORD").ItemId: Simulation.Constant_RECORD
        //LeafElements("ReadValue_DECIMAL").ItemId: Simulation.ReadValue_DECIMAL
        //LeafElements("Ramp 0:360 (1 s)").ItemId: Simulation.Ramp 0:360 (1 s)
        //LeafElements("Constant_NULL").ItemId: Simulation.Constant_NULL
        //LeafElements("ReadValue_ArrayOfUI2").ItemId: Simulation.ReadValue_ArrayOfUI2
        //LeafElements("ReadValue_ArrayOfUI1").ItemId: Simulation.ReadValue_ArrayOfUI1
        //LeafElements("ReadValue_ArrayOfUI4").ItemId: Simulation.ReadValue_ArrayOfUI4
        //LeafElements("Constant_CY").ItemId: Simulation.Constant_CY
        //LeafElements("Staircase 0:2 (1 min)").ItemId: Simulation.Staircase 0:2 (1 min)
        //LeafElements("Staircase 0:2 (10 min)").ItemId: Simulation.Staircase 0:2 (10 min)
        //LeafElements("Square (10 s)").ItemId: Simulation.Square(10 s)
        //LeafElements("Register_ArrayOfBSTR").ItemId: Simulation.Register_ArrayOfBSTR
        //LeafElements("ReadValue_I2").ItemId: Simulation.ReadValue_I2
        //LeafElements("ReadValue_I1").ItemId: Simulation.ReadValue_I1
        //LeafElements("ReadValue_I4").ItemId: Simulation.ReadValue_I4
        //LeafElements("Ramp (1 s)").ItemId: Simulation.Ramp(1 s)
        //LeafElements("ReadValue_ArrayOfDATE").ItemId: Simulation.ReadValue_ArrayOfDATE
        //LeafElements("OnOff (1 s)").ItemId: Simulation.OnOff(1 s)
        //LeafElements("AlternatingQuality Uncertain (1 s)").ItemId: Simulation.AlternatingQuality Uncertain(1 s)
        //LeafElements("Register_NULL").ItemId: Simulation.Register_NULL
        //LeafElements("Random (1 min)").ItemId: Simulation.Random(1 min)
        //LeafElements("Random (10 min)").ItemId: Simulation.Random(10 min)
        //LeafElements("AlternatingError (10 s)").ItemId: Simulation.AlternatingError(10 s)
        //LeafElements("ReadValue_ArrayOfI1").ItemId: Simulation.ReadValue_ArrayOfI1
        //LeafElements("ReadValue_ArrayOfI2").ItemId: Simulation.ReadValue_ArrayOfI2
        //LeafElements("ReadValue_UI2").ItemId: Simulation.ReadValue_UI2
        //LeafElements("ReadValue_ArrayOfI4").ItemId: Simulation.ReadValue_ArrayOfI4
        //LeafElements("ReadValue_UI1").ItemId: Simulation.ReadValue_UI1
        //LeafElements("ReadValue_UI4").ItemId: Simulation.ReadValue_UI4
        //LeafElements("Weekdays (1 s)").ItemId: Simulation.Weekdays(1 s)
        //LeafElements("AlternatingQuality Uncertain (1 min)").ItemId: Simulation.AlternatingQuality Uncertain(1 min)
        //LeafElements("AlternatingQuality Uncertain (10 min)").ItemId: Simulation.AlternatingQuality Uncertain(10 min)
        //LeafElements("Weekdays (1 min)").ItemId: Simulation.Weekdays(1 min)
        //LeafElements("Weekdays (10 min)").ItemId: Simulation.Weekdays(10 min)
        //LeafElements("OnOff (10 s)").ItemId: Simulation.OnOff(10 s)
        //LeafElements("ReadWriteCount").ItemId: Simulation.ReadWriteCount
        //LeafElements("Register_UNKNOWN").ItemId: Simulation.Register_UNKNOWN
        //LeafElements("AlternatingQuality Uncertain (10 s)").ItemId: Simulation.AlternatingQuality Uncertain(10 s)
        //LeafElements("Constant_BSTR").ItemId: Simulation.Constant_BSTR
        //LeafElements("Constant_ERROR").ItemId: Simulation.Constant_ERROR
        //LeafElements("Constant_UI2").ItemId: Simulation.Constant_UI2
        //LeafElements("Constant_UI1").ItemId: Simulation.Constant_UI1
        //LeafElements("Constant_UI4").ItemId: Simulation.Constant_UI4
        //LeafElements("Constant_R4").ItemId: Simulation.Constant_R4
        //LeafElements("Constant_R8").ItemId: Simulation.Constant_R8
        //LeafElements("ReadValue_ArrayOfBSTR").ItemId: Simulation.ReadValue_ArrayOfBSTR
        //LeafElements("Register_ArrayOfR4").ItemId: Simulation.Register_ArrayOfR4
        //LeafElements("Register_ArrayOfR8").ItemId: Simulation.Register_ArrayOfR8
        //LeafElements("Ramp 0:360 (1 min)").ItemId: Simulation.Ramp 0:360 (1 min)
        //LeafElements("Ramp 0:360 (10 min)").ItemId: Simulation.Ramp 0:360 (10 min)
        //LeafElements("RegisterSet_n").ItemId: 
        //LeafElements("Register_ArrayOfUI4").ItemId: Simulation.Register_ArrayOfUI4
        //LeafElements("Register_ArrayOfUI1").ItemId: Simulation.Register_ArrayOfUI1
        //LeafElements("Register_ArrayOfUI2").ItemId: Simulation.Register_ArrayOfUI2
        //LeafElements("Register").ItemId: Simulation.Register
        //LeafElements("Constant_EMPTY").ItemId: Simulation.Constant_EMPTY
        //LeafElements("Register_RECORD").ItemId: Simulation.Register_RECORD
        //LeafElements("ReadValue_ArrayOfBOOL").ItemId: Simulation.ReadValue_ArrayOfBOOL
        //LeafElements("AlternatingError (1 min)").ItemId: Simulation.AlternatingError(1 min)
        //LeafElements("AlternatingError (10 min)").ItemId: Simulation.AlternatingError(10 min)
        //LeafElements("OnOff (1 min)").ItemId: Simulation.OnOff(1 min)
        //LeafElements("ReadValue_DATE").ItemId: Simulation.ReadValue_DATE
        //LeafElements("Register_ERROR").ItemId: Simulation.Register_ERROR
        //LeafElements("ReadValue_ArrayOfUINT").ItemId: Simulation.ReadValue_ArrayOfUINT
        //LeafElements("Incrementing (10 s)").ItemId: Simulation.Incrementing(10 s)
        //LeafElements("ReadValue_ArrayOfINT").ItemId: Simulation.ReadValue_ArrayOfINT
        //LeafElements("ReadValue_BOOL").ItemId: Simulation.ReadValue_BOOL
        //LeafElements("Register_ArrayOfCY").ItemId: Simulation.Register_ArrayOfCY
        //LeafElements("Incrementing (1 s)").ItemId: Simulation.Incrementing(1 s)
        //LeafElements("Constant_UINT").ItemId: Simulation.Constant_UINT
        //LeafElements("ReadValue_ArrayOfR4").ItemId: Simulation.ReadValue_ArrayOfR4
        //LeafElements("ReadValue_ArrayOfR8").ItemId: Simulation.ReadValue_ArrayOfR8
        //LeafElements("Constant_I4").ItemId: Simulation.Constant_I4
        //LeafElements("Constant_I2").ItemId: Simulation.Constant_I2
        //LeafElements("Constant_I1").ItemId: Simulation.Constant_I1
        //LeafElements("Register_BOOL").ItemId: Simulation.Register_BOOL
        //LeafElements("Constant_UNKNOWN").ItemId: Simulation.Constant_UNKNOWN
        //LeafElements("Ramp 0:100 (1 s)").ItemId: Simulation.Ramp 0:100 (1 s)
        //LeafElements("Register_UI4").ItemId: Simulation.Register_UI4
        //LeafElements("Register_UI2").ItemId: Simulation.Register_UI2
        //LeafElements("Register_UI1").ItemId: Simulation.Register_UI1
        //LeafElements("AlternatingError (1 s)").ItemId: Simulation.AlternatingError(1 s)
        //LeafElements("Sine (10 s)").ItemId: Simulation.Sine(10 s)
        //LeafElements("Constant_BOOL").ItemId: Simulation.Constant_BOOL
        //LeafElements("Sine -100:100 (10 s)").ItemId: Simulation.Sine -100:100 (10 s)
        //LeafElements("Register_UINT").ItemId: Simulation.Register_UINT
        //LeafElements("Constant").ItemId: Simulation.Constant
        //LeafElements("Sine (1 s)").ItemId: Simulation.Sine(1 s)
        //LeafElements("Register_I1").ItemId: Simulation.Register_I1
        //LeafElements("Register_I2").ItemId: Simulation.Register_I2
        //LeafElements("Register_I4").ItemId: Simulation.Register_I4
        //LeafElements("ReadValue_ArrayOfCY").ItemId: Simulation.ReadValue_ArrayOfCY
        //LeafElements("Register_ArrayOfUINT").ItemId: Simulation.Register_ArrayOfUINT
        //LeafElements("Incrementing (1 min)").ItemId: Simulation.Incrementing(1 min)
        //LeafElements("Weekdays (10 s)").ItemId: Simulation.Weekdays(10 s)
        //LeafElements("Square (1 s)").ItemId: Simulation.Square(1 s)
        //LeafElements("Sine (1 min)").ItemId: Simulation.Sine(1 min)
        //LeafElements("Sine (10 min)").ItemId: Simulation.Sine(10 min)
        //LeafElements("Constant_DISPATCH").ItemId: Simulation.Constant_DISPATCH
        //LeafElements("Ramp 0:100 (1 min)").ItemId: Simulation.Ramp 0:100 (1 min)
        //LeafElements("Ramp 0:100 (10 min)").ItemId: Simulation.Ramp 0:100 (10 min)
        //LeafElements("Random (1 s)").ItemId: Simulation.Random(1 s)
        //LeafElements("Staircase 0:10 (1 min)").ItemId: Simulation.Staircase 0:10 (1 min)
        //LeafElements("Staircase 0:10 (10 min)").ItemId: Simulation.Staircase 0:10 (10 min)
        //LeafElements("AlternatingQuality Bad (1 s)").ItemId: Simulation.AlternatingQuality Bad(1 s)
        //LeafElements("Sine -100:100 (1 s)").ItemId: Simulation.Sine -100:100 (1 s)
        //LeafElements("Register_ArrayOfDATE").ItemId: Simulation.Register_ArrayOfDATE
        //LeafElements("AlternatingQuality Bad (10 s)").ItemId: Simulation.AlternatingQuality Bad(10 s)
        //LeafElements("ReadValue_R4").ItemId: Simulation.ReadValue_R4
        //LeafElements("ReadValue_R8").ItemId: Simulation.ReadValue_R8
        //LeafElements("Ramp (1 min)").ItemId: Simulation.Ramp(1 min)
        //LeafElements("Ramp (10 min)").ItemId: Simulation.Ramp(10 min)
        //LeafElements("Register_DISPATCH").ItemId: Simulation.Register_DISPATCH
        //LeafElements("OnOff (10 min)").ItemId: Simulation.OnOff(10 min)
        //LeafElements("ReadValue_BSTR").ItemId: Simulation.ReadValue_BSTR
        //LeafElements("Staircase 0:10 (10 s)").ItemId: Simulation.Staircase 0:10 (10 s)
        //LeafElements("Random (10 s)").ItemId: Simulation.Random(10 s)
        //LeafElements("Incrementing").ItemId: Simulation.Incrementing
        //LeafElements("Register_BSTR").ItemId: Simulation.Register_BSTR
        //LeafElements("ReadValue_UINT").ItemId: Simulation.ReadValue_UINT
        //LeafElements("Register_CY").ItemId: Simulation.Register_CY
        //LeafElements("AlternatingQuality Bad (1 min)").ItemId: Simulation.AlternatingQuality Bad(1 min)
        //LeafElements("AlternatingQuality Bad (10 min)").ItemId: Simulation.AlternatingQuality Bad(10 min)
        //LeafElements("Random").ItemId: Simulation.Random
        //LeafElements("Sine -100:100 (1 min)").ItemId: Simulation.Sine -100:100 (1 min)
        //LeafElements("Sine -100:100 (10 min)").ItemId: Simulation.Sine -100:100 (10 min)
        //LeafElements("Ramp (10 s)").ItemId: Simulation.Ramp(10 s)
        //LeafElements("ReadValue_INT").ItemId: Simulation.ReadValue_INT
        //LeafElements("Staircase 0:2 (1 s)").ItemId: Simulation.Staircase 0:2 (1 s)
        //LeafElements("ReadValue_CY").ItemId: Simulation.ReadValue_CY
        //LeafElements("Register_R8").ItemId: Simulation.Register_R8
        //LeafElements("Register_R4").ItemId: Simulation.Register_R4
        //LeafElements("Register_DECIMAL").ItemId: Simulation.Register_DECIMAL
        //LeafElements("Incrementing (10 min)").ItemId: Simulation.Incrementing(10 min)
        //LeafElements("Register_EMPTY").ItemId: Simulation.Register_EMPTY
        //LeafElements("Constant_INT").ItemId: Simulation.Constant_INT
        //LeafElements("Register_INT").ItemId: Simulation.Register_INT
        //LeafElements("Register_ArrayOfBOOL").ItemId: Simulation.Register_ArrayOfBOOL
        //LeafElements("Ramp 0:100 (10 s)").ItemId: Simulation.Ramp 0:100 (10 s)
        //LeafElements("Ramp 0:360 (10 s)").ItemId: Simulation.Ramp 0:360 (10 s)
        //LeafElements("Square (1 min)").ItemId: Simulation.Square(1 min)
        //LeafElements("Square (10 min)").ItemId: Simulation.Square(10 min)
        //LeafElements("Constant_DECIMAL").ItemId: Simulation.Constant_DECIMAL
        //LeafElements("Register_VARIANT").ItemId: Simulation.Register_VARIANT
        //LeafElements("Constant_DATE").ItemId: Simulation.Constant_DATE
        //LeafElements("Register_ArrayOfINT").ItemId: Simulation.Register_ArrayOfINT
    }
}

 

The most generic address space browsing method is BrowseNodes. It combines the functionality of BrowseBranches and BrowseLeaves, and it also allows the widest range of filtering options by passing in an argument of type DABrowseParameters, or individual arguments for data type filter and access rights filter.

// This example shows how to obtain all nodes under the "Simulation" branch of the address space. For each node, it displays
// whether the node is a branch or a leaf.

using System;
using OpcLabs.EasyOpc.DataAccess;
using OpcLabs.EasyOpc.DataAccess.AddressSpace;
using OpcLabs.EasyOpc.OperationModel;

namespace DocExamples.DataAccess._EasyDAClient
{
    partial class BrowseNodes
    {
        public static void Main1()
        {
            // Instantiate the client object.
            var client = new EasyDAClient();

            DANodeElementCollection nodeElements;
            try
            {
                nodeElements = client.BrowseNodes("", "OPCLabs.KitServer.2", "Greenhouse", DABrowseParameters.Default);
            }
            catch (OpcException opcException)
            {
                Console.WriteLine($"*** Failure: {opcException.GetBaseException().Message}");
                return;
            }

            foreach (DANodeElement nodeElement in nodeElements)
            {
                Console.WriteLine($"NodeElements(\"{nodeElement.Name}\"):");
                Console.WriteLine($"    .IsBranch: {nodeElement.IsBranch}");
                Console.WriteLine($"    .IsLeaf: {nodeElement.IsLeaf}");
            }
        }
    }
}

More Examples

// This example shows how to recursively browse the nodes in the OPC address space.

using System;
using System.Diagnostics;
using OpcLabs.EasyOpc;
using OpcLabs.EasyOpc.DataAccess;
using OpcLabs.EasyOpc.DataAccess.AddressSpace;
using OpcLabs.EasyOpc.OperationModel;

namespace DocExamples.DataAccess._EasyDAClient
{
    partial class BrowseNodes
    {
        public static void Recursive()
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();

            // Instantiate the client object.
            var client = new EasyDAClient();
            _branchCount = 0;
            _leafCount = 0;

            try
            {
                BrowseFromNode(client, "OPCLabs.KitServer.2", "");
            }
            catch (OpcException opcException)
            {
                Console.WriteLine("*** Failure: {0}", opcException.GetBaseException().Message);
                return;
            }

            stopwatch.Stop();
            Console.WriteLine("Browsing has taken (milliseconds): {0}", stopwatch.ElapsedMilliseconds);
            Console.WriteLine("Branch count: {0}", _branchCount);
            Console.WriteLine("Leaf count: {0}", _leafCount);
        }

        private static void BrowseFromNode(
            EasyDAClient client,
            ServerDescriptor serverDescriptor,
            DANodeDescriptor parentNodeDescriptor)
        {
            Debug.Assert(client != null);
            Debug.Assert(serverDescriptor != null);
            Debug.Assert(parentNodeDescriptor != null);

            // Obtain all node elements under parentNodeDescriptor
            var browseParameters = new DABrowseParameters();    // no filtering whatsoever
            DANodeElementCollection nodeElementCollection =
                client.BrowseNodes(serverDescriptor, parentNodeDescriptor, browseParameters);
            // Remark: that BrowseNodes(...) may also throw OpcException; a production code should contain handling for 
            // it, here omitted for brevity.

            foreach (DANodeElement nodeElement in nodeElementCollection)
            {
                Debug.Assert(nodeElement != null);

                Console.WriteLine(nodeElement);

                // If the node is a branch, browse recursively into it.
                if (nodeElement.IsBranch)
                {
                    _branchCount++;
                    BrowseFromNode(client, serverDescriptor, nodeElement);
                }
                else
                {
                    _leafCount++;
                }
            }
        }

        private static int _branchCount;
        private static int _leafCount;
    }
}
// This example shows how to recursively browse the nodes in the OPC XML-DA address space.

using System;
using System.Diagnostics;
using OpcLabs.EasyOpc;
using OpcLabs.EasyOpc.DataAccess;
using OpcLabs.EasyOpc.DataAccess.AddressSpace;
using OpcLabs.EasyOpc.OperationModel;

namespace DocExamples.DataAccess.Xml
{
    class BrowseNodes
    {
        public static void RecursiveXml()
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();

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

            _branchCount = 0;
            _leafCount = 0;

            try
            {
                BrowseFromNode(client, "http://opcxml.demo-this.com/XmlDaSampleServer/Service.asmx", "");
            }
            catch (OpcException opcException)
            {
                Console.WriteLine("*** Failure: {0}", opcException.GetBaseException().Message);
                return;
            }

            stopwatch.Stop();
            Console.WriteLine("Browsing has taken (milliseconds): {0}", stopwatch.ElapsedMilliseconds);
            Console.WriteLine("Branch count: {0}", _branchCount);
            Console.WriteLine("Leaf count: {0}", _leafCount);
        }

        private static void BrowseFromNode(
            EasyDAClient client,
            ServerDescriptor serverDescriptor,
            DANodeDescriptor parentNodeDescriptor)
        {
            Debug.Assert(client != null);
            Debug.Assert(serverDescriptor != null);
            Debug.Assert(parentNodeDescriptor != null);

            // Obtain all node elements under parentNodeDescriptor
            var browseParameters = new DABrowseParameters();    // no filtering whatsoever
            DANodeElementCollection nodeElementCollection =
                client.BrowseNodes(serverDescriptor, parentNodeDescriptor, browseParameters);
            // Remark: that BrowseNodes(...) may also throw OpcException; a production code should contain handling for 
            // it, here omitted for brevity.

            foreach (DANodeElement nodeElement in nodeElementCollection)
            {
                Debug.Assert(nodeElement != null);

                Console.WriteLine(nodeElement);

                // If the node is a branch, browse recursively into it.
                if (nodeElement.IsBranch)
                {
                    _branchCount++;
                    BrowseFromNode(client, serverDescriptor, nodeElement);
                }
                else
                {
                    _leafCount++;
                }
            }
        }

        private static int _branchCount;
        private static int _leafCount;
    }
}
QuickOPC supports OPC XML-DA also on Linux and macOS.
// Recursively browses and displays the nodes in the OPC address space, and attempts to read and display values of all OPC 
// items it finds.

using System;
using System.Diagnostics;
using OpcLabs.EasyOpc.DataAccess;
using OpcLabs.EasyOpc.DataAccess.AddressSpace;
using OpcLabs.EasyOpc.OperationModel;

namespace DocExamples.DataAccess._EasyDAClient
{
    partial class BrowseNodes
    {
        const string ServerClass = "OPCLabs.KitServer.2";

        // Instantiate the client object.
        static readonly EasyDAClient Client = new EasyDAClient();

        static void BrowseAndReadFromNode(string parentItemId)
        {
            // Obtain all node elements under parentItemId
            var browseParameters = new DABrowseParameters(); // no filtering whatsoever
            DANodeElementCollection nodeElementCollection = Client.BrowseNodes("", ServerClass, parentItemId,
                browseParameters);
            // Remark: that BrowseNodes(...) may also throw OpcException; a production code should contain handling for it, here 
            // omitted for brevity.

            foreach (DANodeElement nodeElement in nodeElementCollection)
            {
                Debug.Assert(nodeElement != null);

                // If the node is a leaf, it might be possible to read from it
                if (nodeElement.IsLeaf)
                {
                    // Determine what the display - either the value read, or exception message in case of failure.
                    string display;
                    try
                    {
                        object value = Client.ReadItemValue("", ServerClass, nodeElement);
                        display = $"{value}";
                    }
                    catch (OpcException exception)
                    {
                        display = $"** {exception.GetBaseException().Message} **";
                    }

                    Console.WriteLine("{0} -> {1}", nodeElement.ItemId, display);
                }
                // If the node is not a leaf, just display its itemId
                else
                    Console.WriteLine("{0}", nodeElement.ItemId);

                // If the node is a branch, browse recursively into it.
                if (nodeElement.IsBranch &&
                    (nodeElement.ItemId != "SimulateEvents")
                    /* this branch is too big for the purpose of this example */)
                    BrowseAndReadFromNode(nodeElement);
            }
        }

        public static void RecursiveWithRead()
        {
            Console.WriteLine("Browsing and reading values...");
            // Set timeout to only wait 1 second - default would be 1 minute to wait for good quality that may never come.
            Client.InstanceParameters.Timeouts.ReadItem = 1000;

            // Do the actual browsing and reading, starting from root of OPC address space (denoted by empty string for itemId)
            try
            {
                BrowseAndReadFromNode("");
            }
            catch (OpcException opcException)
            {
                Console.WriteLine("*** Failure: {0}", opcException.GetBaseException().Message);
            }
        }
    }
}

 

 

Inheritance Hierarchy

System.Object
   OpcLabs.BaseLib.Object2
      OpcLabs.BaseLib.Info
         OpcLabs.BaseLib.Parameters
            OpcLabs.EasyOpc.DataAccess.DABrowseParameters

Requirements

Target Platforms: .NET Framework: Windows 10 (selected versions), Windows 11 (selected versions), Windows Server 2012, Windows Server 2016; .NET Core, .NET 5, .NET 6: Linux, macOS, Microsoft Windows

See Also

Reference

DABrowseParameters Members
OpcLabs.EasyOpc.DataAccess Namespace