0

My C# application uses the OPC UA Core stack as a Client to connect with a PLC running as a Server. I am not using the OPC UA SDK because the application is WPF and the SDK is incomprehensible.

I've consulted various references (including the OPC UA SDK and Converter Systems LLC WPF toolkit) and cobbled together my own method for configuring an ITransportChannel object to pass to the Opc.UaSessionClient constructor.

The problem I'm facing is that, in order to obtain an endpoint description and configuration that match the Server's expected values, I use the ConfiguredEndpoint.UpdateFromServer, but this throws a ServiceResultException(BadSecureChannelClosed) when its DiscoveryClient object is closed.

I don't see this exception being reported by the SimpleOpClient project included with the SDK (which is not in any way simple).

Any ideas what could be wrong with this function?

    private static ITransportChannel CreateTransportChannel(
        ApplicationConfiguration appConfig,
        String discoveryUrl)
    {
        // parse the selected URL.
        Uri uri = new Uri(discoveryUrl);

        EndpointDescription endpointDescription = new EndpointDescription
        {
            EndpointUrl = uri.ToString(),
            SecurityMode = MessageSecurityMode.None,
            SecurityPolicyUri = "http://opcfoundation.org/UA/SecurityPolicy#None"
        };

        // Configure the endpoint.
        ServiceMessageContext messageContext = appConfig.CreateMessageContext();
        EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(appConfig);
        ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);

        // The server may require that the endpoint configuration be adjusted
        // to match its own settings.
        if (endpoint.UpdateBeforeConnect)
        {
            // Update endpoint description using the discovery endpoint.
// EXCEPTION thrown during this call.
            endpoint.UpdateFromServer(BindingFactory.Create(appConfig, messageContext));

            endpointDescription = endpoint.Description;
            endpointConfiguration = endpoint.Configuration;
        }

        // Sanity check for the presence of required security certificates.
        X509Certificate2 clientCertificate = null;
        if (endpointDescription.SecurityPolicyUri != SecurityPolicies.None)
        {
            if (appConfig.SecurityConfiguration.ApplicationCertificate == null)
            {
                Utils.Trace("ApplicationCertificate missing from Configuration.");
                throw ServiceResultException.Create(StatusCodes.BadConfigurationError,
                    "ApplicationCertificate must be specified.");
            }

            clientCertificate = appConfig.SecurityConfiguration.ApplicationCertificate.Find(true);
            if (clientCertificate == null)
            {
                Utils.Trace("ApplicationCertificate file could not be found.");
                throw ServiceResultException.Create(StatusCodes.BadConfigurationError,
                    "ApplicationCertificate cannot be found.");
            }
        }

        // Create a transport channel.
        return SessionChannel.Create(
            appConfig,
            endpointDescription,
            endpointConfiguration,
            clientCertificate,
            messageContext);
    }

Is it the server returning a BadSecureChannelClosed result? If so, why? Or is it one of the multitude of internal exceptions that are thrown by the stack?

Evil Dog Pie
  • 2,300
  • 2
  • 23
  • 46

1 Answers1

2

First, your code works fine. It updates the endpoint even though it throws that exception. It's a handled exception of the opc.ua.core library whenever the library closes a socket. You see it in the debugger if you have selected "All Common Language Runtime Exceptions not in this list" in the "Exception Settings" window.

Second, for those of us using the OPC Foundatation code at UA-.NET you will be happy to know that the Session.Create() constructor will update endpoints automatically, if the parameter is true. See this post for an example. OPC UA : minimal code that browses the root node of a server

Also, since you found my original WPF Toolkit I would like to invite you to my new and improved WPF and UAP Toolkit hosted on GitHub.

Community
  • 1
  • 1
Andrew Cullen
  • 838
  • 8
  • 14
  • The new toolkit looks great and I would be very pleased to use it if my application needed a significant part of the functionality. The original one was immensely useful to me as a way to understand which parts of the SDK were necessary and which I could lose. – Evil Dog Pie Jun 30 '16 at 17:49
  • My application only needs a few functions (once the session is open): it reads an array of eight `Int16` integers up to 40 times per second, polls a 'tick counter' as a heartbeat once per second, and occasionally writes a `Boolean` to enable a remote procedure call. This makes 90% of the SDK redundant. I've cobbled together a *really* simple client, using just the OPC UA Core in about 2,000 lines of code. – Evil Dog Pie Jun 30 '16 at 17:53
  • One of the biggest frustrations I have with the SDK and stack (as opposed to your toolkit) are that they appear to use exceptions as a mechanism for returning error conditions. Very few of them actually seem to indicate that something has become unusable, so the client code becomes cluttered with `try...catch` blocks that largely do nothing other than ignore the exception. – Evil Dog Pie Jun 30 '16 at 17:57
  • " if the parameter is true". Which parameter? `updateBeforeConnect`? – astrowalker Nov 21 '16 at 07:51