13

I am using the OPC UA Foundation SDK to develop a small client. What would be the minimal C# code to:

  • Connect to a server
  • Browse the root node
  • Print the immediate children's BrowseNames
  • Quit?

I am given the server endpoint (no discovery), security None.

The code should make no use of config files, nor require a STA.

Any help on this would be more than appreciated.

Laurent LA RIZZA
  • 2,905
  • 1
  • 23
  • 41

1 Answers1

42

Edit 4/2018:

The OPC UA .Net Standard Library is going asynchronous. See the updated sample.

Edit 9/2016:

Everyone should see the new OPC UA .Net Standard Library.

You can develop apps that run on all common platforms available today, including Linux, iOS, Android (via Xamarin) and Windows.

And you can find many samples, including a sample inspired by this post. Look for the folder SampleApplications/Samples/NetCoreConsoleClient.

Original post:

Help with homework, perhaps?

using Opc.Ua;   // Install-Package OPCFoundation.NetStandard.Opc.Ua
using Opc.Ua.Client;
using Opc.Ua.Configuration;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;

namespace MyHomework
{
  class Program
  {
    static void Main(string[] args)
    {

        Console.WriteLine("Step 1 - Create application configuration and certificate.");
        var config = new ApplicationConfiguration()
        {
            ApplicationName = "MyHomework",
            ApplicationUri = Utils.Format(@"urn:{0}:MyHomework", System.Net.Dns.GetHostName()),
            ApplicationType = ApplicationType.Client,
            SecurityConfiguration = new SecurityConfiguration {
                ApplicationCertificate = new CertificateIdentifier { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\MachineDefault", SubjectName="MyHomework" },
                TrustedIssuerCertificates = new CertificateTrustList { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\UA Certificate Authorities" },
                TrustedPeerCertificates = new CertificateTrustList { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\UA Applications" },
                RejectedCertificateStore = new CertificateTrustList { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\RejectedCertificates" },
                AutoAcceptUntrustedCertificates = true
            },
            TransportConfigurations = new TransportConfigurationCollection(),
            TransportQuotas = new TransportQuotas { OperationTimeout = 15000 },
            ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 },
            TraceConfiguration = new TraceConfiguration()
        };
        config.Validate(ApplicationType.Client).GetAwaiter().GetResult();
        if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates)
        {
            config.CertificateValidator.CertificateValidation += (s, e) => { e.Accept = (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted); };
        }

        var application = new ApplicationInstance
        {
            ApplicationName = "MyHomework",
            ApplicationType = ApplicationType.Client,
            ApplicationConfiguration = config
        };
        application.CheckApplicationInstanceCertificate(false, 2048).GetAwaiter().GetResult();

        var selectedEndpoint = CoreClientUtils.SelectEndpoint("opc.tcp://" + Dns.GetHostName() + ":48010", useSecurity: true, operationTimeout: 15000);

        Console.WriteLine($"Step 2 - Create a session with your server: {selectedEndpoint.EndpointUrl} ");
        using (var session = Session.Create(config, new ConfiguredEndpoint(null, selectedEndpoint, EndpointConfiguration.Create(config)), false, "", 60000, null, null).GetAwaiter().GetResult())
        {
            Console.WriteLine("Step 3 - Browse the server namespace.");
            ReferenceDescriptionCollection refs;
            Byte[] cp;
            session.Browse(null, null, ObjectIds.ObjectsFolder, 0u, BrowseDirection.Forward, ReferenceTypeIds.HierarchicalReferences, true, (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, out cp, out refs);
            Console.WriteLine("DisplayName: BrowseName, NodeClass");
            foreach (var rd in refs)
            {
                Console.WriteLine("{0}: {1}, {2}", rd.DisplayName, rd.BrowseName, rd.NodeClass);
                ReferenceDescriptionCollection nextRefs;
                byte[] nextCp;
                session.Browse(null, null, ExpandedNodeId.ToNodeId(rd.NodeId, session.NamespaceUris), 0u, BrowseDirection.Forward, ReferenceTypeIds.HierarchicalReferences, true, (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, out nextCp, out nextRefs);
                foreach (var nextRd in nextRefs)
                {
                    Console.WriteLine("+ {0}: {1}, {2}", nextRd.DisplayName, nextRd.BrowseName, nextRd.NodeClass);
                }
            }

            Console.WriteLine("Step 4 - Create a subscription. Set a faster publishing interval if you wish.");
            var subscription = new Subscription(session.DefaultSubscription) { PublishingInterval = 1000 };

            Console.WriteLine("Step 5 - Add a list of items you wish to monitor to the subscription.");
            var list = new List<MonitoredItem> { new MonitoredItem(subscription.DefaultItem) { DisplayName = "ServerStatusCurrentTime", StartNodeId = "i=2258" } };
            list.ForEach(i => i.Notification += OnNotification);
            subscription.AddItems(list);

            Console.WriteLine("Step 6 - Add the subscription to the session.");
            session.AddSubscription(subscription);
            subscription.Create();

            Console.WriteLine("Press any key to remove subscription...");
            Console.ReadKey(true);
        }

        Console.WriteLine("Press any key to exit...");
        Console.ReadKey(true);
    }

    private static void OnNotification(MonitoredItem item, MonitoredItemNotificationEventArgs e)
    {
        foreach (var value in item.DequeueValues())
        {
            Console.WriteLine("{0}: {1}, {2}, {3}", item.DisplayName, value.Value, value.SourceTimestamp, value.StatusCode);
        }
    }

  }
}
Andrew Cullen
  • 838
  • 8
  • 14
  • 4
    Sounds like homework, but it's not. I am trying to untangle some dependency-ridden OPC UA code, and I had great trouble programmatically creating a minimal ApplicationConfiguration to write a unit test. – Laurent LA RIZZA Jun 03 '15 at 20:33
  • Works like a charm. Thank you. – Laurent LA RIZZA Jun 04 '15 at 13:03
  • 1
    Thank you so much! The sample code provided (sample client) was very poor.. your example helped me much! – Jeroen van Langen Apr 22 '16 at 19:58
  • 2
    This is great. Thanks. The OPC UA SDK should really include a sample CLI application (like this) that demonstrates how to get a minimal application up and running from scratch. – v3gard Sep 19 '16 at 09:24
  • Good example but i'm getting the following error: Task does not have any definition of browse method. Can anyone help? Thanks. – Maha Benabbou Apr 05 '17 at 14:35
  • 1
    The OPC UA .NETStandard Library is going asynchronous! Now you get a Task from Session.Create(). See an updated sample at https://github.com/OPCFoundation/UA-.NETStandardLibrary/tree/master/SampleApplications/Samples/NetCoreConsoleClient – Andrew Cullen Apr 06 '17 at 15:14
  • Thanks andrewcullen! – Maha Benabbou Apr 12 '17 at 07:30
  • I retied this example, but now at `config.Validate(ApplicationType.Client).GetAwaiter().GetResult();` gives a null reference... any thoughts? – Jeroen van Langen Sep 17 '18 at 12:16
  • I foillowed this example but get the error ApllicationCertificate cannot be found. Any ideas? – Jesse Aug 22 '19 at 12:49
  • I followed this application and get following error at start:System.IO.FileNotFoundException: 'Could not load file or assembly 'System.ServiceModel.Primitives, Version=4.1.1.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.' – SWIK Dec 01 '19 at 17:39
  • Weirdly enough, an application certificate is given in the new version of the code (SecurityConfiguration), which was not present in the original answer. Now the answer does not seem to answer the question anymore (security = None), and the ApplicationConfiguration does not seem minimal enough to allow to write a simple UT anymore (you’re tied to certificate stores now) Maybe @andrewcullen could help on that one. – Laurent LA RIZZA May 25 '20 at 18:00
  • 1
    If you prefer to turn off encryption, then set "useSecurity: false " – Andrew Cullen May 26 '20 at 04:37
  • 1
    If you prefer to not generate an application certificate then remove call to: "CheckApplicationInstanceCertificate" – Andrew Cullen May 26 '20 at 04:40
  • 1
    And if you want to not use the certificate directory store then: `SecurityConfiguration = new SecurityConfiguration { ApplicationCertificate = new CertificateIdentifier(), AutoAcceptUntrustedCertificates = true, }` – Andrew Cullen May 26 '20 at 04:41
  • @AndrewCullen: I'm getting the following error: "Certificate doesn't meet minimum key length requirement.". Do you know the reason? – Imran Sh May 14 '21 at 10:08
  • The line to CheckApplicationInstanceCertificate may have found an older cert that did not have a PublicKey length of 2048. You may have to delete the "MyHomework" cert from C:\ProgramData\OPC Foundation\CertificateStores\MachineDefault\certs and run the program again. A new cert with the correct key length will be created. – Andrew Cullen May 16 '21 at 16:33