QuickOPC User's Guide and Reference
Specialized Client Objects
Features > Specialized Client Objects
In This Topic

A specialized client object builds on top of a general-purpose client object (such as EasyUAClient) and provides functionality that is relevant for specific problem domain. It contains, in a sense, pre-packaged pieces of reusable code that the developer would typically need to write, whenever he needs to develop a solution for that problem domain.

In OPC UA, the problem domain addressed by the specialized client object is often a selected part of the OPC UA specification. This is due to the layered architecture of OPC UA, where additional informational models can be used to enhance the functionality and address new problem domains, while the basic set of services (covered by the general-purpose client object) remains static and relatively small.

Specialized Client Derivation

A specialized client object can be created from an existing general-purpose client (such as when you have the IEasyUAClient Interface) using so-called derivation. For derivation, there is a method (or an extension method) on the general-purpose client, that returns the specialized client needed. For example, you can call the AsGlobalDiscoveryClient (Extension) Method on the IEasyUAClient Interface, and you will receive back a specialized client object for OPC UA global discovery.

A specialized client object created using derivation performs its operations using the general-purpose client object that it was derived from, and therefore also uses all its settings, always shares the same connections, etc. You can then think of the specialized client simply as a functionality extension of the general-purpose client object.

It is recommended that you use the specialized client derivation whenever you have a suitable general-purpose client object available.

Standalone Specialized Clients

A specialized client object can also be created standalone, without having a general-purpose client object first. This is done simply by instantiating the specialized client object, e.g. EasyUAGlobalDiscoveryClient. When created in this way, the specialized client object will use an internal general-purpose client to perform its operations. The parameters of such general-purpose client object, if they are of interest to you, are available in the ClientSelector Property of the specialized client. Note that if you want to change any of these parameters, you must do so before you perform the first operation on the specialized client object. Also note that the internal general-purpose client object may be used for multiple purposes by QuickOPC.

The example below uses a standalone specialized client object to perform OPC UA global discovery operation.

// Shows how to unregister all clients from a GDS.

using System;
using System.Collections.Generic;
using System.Linq;
using OpcLabs.BaseLib.Collections.Generic.Extensions;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.AddressSpace;
using OpcLabs.EasyOpc.UA.Discovery;
using OpcLabs.EasyOpc.UA.Extensions;
using OpcLabs.EasyOpc.UA.Gds;
using OpcLabs.EasyOpc.UA.OperationModel;

namespace UADocExamples.Gds._EasyUAGlobalDiscoveryClient
{
    class UnregisterApplication
    {
        public static void Main1()
        {
            // Define which GDS we will work with.
            UAEndpointDescriptor gdsEndpointDescriptor =
                ((UAEndpointDescriptor)"opc.tcp://opcua.demo-this.com:58810/GlobalDiscoveryServer")
                .WithUserNameIdentity("appadmin", "demo");

            // Instantiate the global discovery client object
            var globalDiscoveryClient = new EasyUAGlobalDiscoveryClient();

            // Find application IDs of all client applications registered in the GDS.
            var clientApplicationIds = new HashSet<UANodeId>();
            try
            {
                globalDiscoveryClient.QueryApplications(
                    gdsEndpointDescriptor: gdsEndpointDescriptor,
                    startingRecordId: 0,
                    maximumRecordsToReturn: 0,
                    applicationName: "",
                    applicationUriString: "",
                    applicationTypes: UAApplicationTypes.Client,
                    productUriString: "",
                    serverCapabilities: new string[0],
                    lastCounterResetTime: out _,
                    nextRecordId: out _,
                    applications: out UAApplicationDescription[] applicationDescriptionArray);

                foreach (UAApplicationDescription applicationDescription in applicationDescriptionArray)
                {
                    var applicationRecordArray = globalDiscoveryClient.FindApplications(
                        gdsEndpointDescriptor,
                        applicationDescription.ApplicationUriString);
                    clientApplicationIds.AddRange(applicationRecordArray.Select(description => description.ApplicationId));
                }
            }
            catch (UAException uaException)
            {
                Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message);
                return;
            }

            // Unregister all client applications found.
            foreach (UANodeId applicationId in clientApplicationIds)
            {
                Console.WriteLine();
                Console.WriteLine("Application ID: {0}", applicationId);

                try
                {
                    globalDiscoveryClient.UnregisterApplication(gdsEndpointDescriptor, applicationId);
                }
                catch (UAException uaException)
                {
                    Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message);
                    continue;
                }
                Console.WriteLine("Unregistered.");
            }
        }
    }
}
// Shows how to unregister all clients from a GDS.

class procedure UnregisterApplication.Main;
var
  ApplicationDescription: _UAApplicationDescription;
  ApplicationDescriptionArray: OleVariant;
  ApplicationId: _UANodeId;
  ApplicationName: WideString;
  ApplicationRecord: _UAApplicationRecordDataType;
  ApplicationRecordArray: OleVariant;
  ApplicationUriString: WideString;
  ClientApplicationIds: TList<_UANodeID>;
  GlobalDiscoveryClient: OpcLabs_EasyOpcUA_TLB._EasyUAGlobalDiscoveryClient;
  GdsEndpointDescriptor: _UAEndpointDescriptor;
  I, J: integer;
  LastCounterResetTime: TDateTime;
  MaximumRecordsToReturn: Integer;
  NextRecordId: Integer;
  ProductUriString: WideString;
  ServerCapabilities: array of string;
  StartingRecordId: Integer;
begin
  // Define which GDS we will work with.
  GdsEndpointDescriptor := CoUAEndpointDescriptor.Create;
  GdsEndpointDescriptor.UrlString := 'opc.tcp://opcua.demo-this.com:58810/GlobalDiscoveryServer';
  GdsEndpointDescriptor.UserIdentity.UserNameTokenInfo.UserName := 'appadmin';
  GdsEndpointDescriptor.UserIdentity.UserNameTokenInfo.Password := 'demo';

  // Instantiate the global discovery client object
  GlobalDiscoveryClient := CoEasyUAGlobalDiscoveryClient.Create;

  // Find application IDs of all client applications registered in the GDS.
  ClientApplicationIds := TList<_UANodeID>.Create();
  StartingRecordId := 0;
  MaximumRecordsToReturn := 0;
  ApplicationName := '';
  ApplicationUriString := '';
  ProductUriString := '';
  try
    GlobalDiscoveryClient.QueryApplications(
      GdsEndpointDescriptor,
      StartingRecordId,
      MaximumRecordsToReturn,
      ApplicationName,
      ApplicationUriString,
      UAApplicationTypes_Client,
      ProductUriString,
      ServerCapabilities,
      LastCounterResetTime,
      NextRecordId,
      ApplicationDescriptionArray);

    for I := VarArrayLowBound(ApplicationDescriptionArray,1) to VarArrayHighBound(ApplicationDescriptionArray,1) do
    begin
      ApplicationDescription := IUnknown(ApplicationDescriptionArray[I]) as _UAApplicationDescription;
      TVarData(ApplicationRecordArray).VType := varArray or varVariant;
      TVarData(ApplicationRecordArray).VArray := PVarArray(GlobalDiscoveryClient.FindApplications(
        GdsEndpointDescriptor, ApplicationDescription.ApplicationUriString));
      for J := VarArrayLowBound(ApplicationRecordArray,1) to VarArrayHighBound(ApplicationRecordArray,1) do
      begin
        ApplicationRecord := IUnknown(ApplicationRecordArray[J]) as _UAApplicationRecordDataType;
        ClientApplicationIds.Add(ApplicationRecord.ApplicationId);
      end;
    end;
  except
    on E: EOleException do
    begin
      WriteLn(Format('*** Failure: %s', [E.GetBaseException.Message]));
    end;
  end;

  // Unregister all client applications found.
  for ApplicationId in ClientApplicationIds do
  begin
    WriteLn;
    WriteLn('Application ID: ', ApplicationId.ToString);
    try
      GlobalDiscoveryClient.UnregisterApplication(
        GdsEndpointDescriptor, ApplicationId);
    except
      on E: EOleException do
      begin
        WriteLn(Format('*** Failure: %s', [E.GetBaseException.Message]));
        Continue;
      end;
    end;
    WriteLn('Unregistered.');
  end;
  FreeAndNil(ClientApplicationIds);
end;
' Shows how to unregister all clients from a GDS.

Imports System.Linq
Imports OpcLabs.BaseLib.Collections.Generic.Extensions
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.AddressSpace
Imports OpcLabs.EasyOpc.UA.Discovery
Imports OpcLabs.EasyOpc.UA.Extensions
Imports OpcLabs.EasyOpc.UA.Gds
Imports OpcLabs.EasyOpc.UA.OperationModel

Namespace UADocExamples.Gds._EasyUAGlobalDiscoveryClient
    Friend Class UnregisterApplication
        Public Shared Sub Main1()

            ' Define which GDS we will work with.
            Dim gdsEndpointDescriptor As UAEndpointDescriptor =
                New UAEndpointDescriptor("opc.tcp://opcua.demo-this.com:58810/GlobalDiscoveryServer") _
                .WithUserNameIdentity("appadmin", "demo")

            ' Instantiate the global discovery client object
            Dim globalDiscoveryClient = New EasyUAGlobalDiscoveryClient()

            ' Find application IDs of all client applications registered in the GDS.
            Dim clientApplicationIds = New HashSet(Of UANodeId)
            Try
                Dim lastCounterResetTime As DateTime
                Dim nextRecordId As Long
                Dim applicationDescriptionArray() As UAApplicationDescription = Nothing
                globalDiscoveryClient.QueryApplications(
                    gdsEndpointDescriptor:=gdsEndpointDescriptor,
                    startingRecordId:=0,
                    maximumRecordsToReturn:=0,
                    applicationName:="",
                    applicationUriString:="",
                    applicationTypes:=UAApplicationTypes.Client,
                    productUriString:="",
                    serverCapabilities:=New String() {},
                    lastCounterResetTime:=lastCounterResetTime,
                    nextRecordId:=nextRecordId,
                    applications:=applicationDescriptionArray)

                For Each applicationDescription As UAApplicationDescription In applicationDescriptionArray
                    Dim applicationRecordArray = globalDiscoveryClient.FindApplications(
                        gdsEndpointDescriptor,
                        applicationDescription.ApplicationUriString)
                    clientApplicationIds.AddRange(applicationRecordArray.Select(Function(description) description.ApplicationId))
                Next applicationDescription
            Catch uaException As UAException
                Console.WriteLine("*** Failure: {0}", uaException.GetBaseException.Message)
                Exit Sub
            End Try

            ' Unregister all client applications found.
            For Each applicationId As UANodeId In clientApplicationIds
                Console.WriteLine()
                Console.WriteLine("Application ID: {0}", applicationId)

                Try
                    globalDiscoveryClient.UnregisterApplication(gdsEndpointDescriptor, applicationId)
                Catch uaException As UAException
                    Console.WriteLine("*** Failure: {0}", uaException.GetBaseException.Message)
                    Continue For
                End Try
                Console.WriteLine("Unregistered.")
            Next applicationId
        End Sub
    End Class
End Namespace

Visual Studio Toolbox

The standalone specialized clients are also available as icons in the Visual Studio Toolbox. This means that in certain types of projects, they can be dragged from the Toolbox to the design surface, and Visual Studio will create code to instantiate and configure the specialized client object. Component properties are then also editable from the Visual Studio (in the Properties tool window).

Reverting to the General-Purpose Client Object

In a similar as you can derive a specialized client object from a general-purpose client, you can go in the opposite direction. If you have a specialized client object at hand, you can use its AsClient method to obtain the client object upon which the specialized client is built. If the specialized client object has been derived from a general-purpose client, this method returns the original general-purpose client object used in derivation. If the specialized client object us standalone, this method returns the internal general-purpose client object used by this specialized client.

The IsDerived Property determines whether a given specialized client object has been derived from a general-purpose client object.

Specialized Clients Catalog

There are currently following specialized client objects available:

The features discussed here, or some of them, may not be available in all editions of the product. Check the Product Editions page for differences between the editions. The trial license has all features enabled (and is limited in period for which it provides valid data), but licenses for specific commercial editions may have functionality limitations.
See Also

Examples - OPC UA File Transfer