Search code examples
c#opc-ua

OPC UA ServiceResultException(BadSecureChannelClosed) updating endpoint from server


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?


Solution

  • 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.