C# OPC UA ServiceResultException(BadSecureChannelClosed)从服务器更新端点

C# OPC UA ServiceResultException(BadSecureChannelClosed)从服务器更新端点,c#,opc-ua,C#,Opc Ua,我的C#应用程序使用OPC UA核心堆栈作为客户端,与作为服务器运行的PLC连接。我没有使用OPC UA SDK,因为应用程序是WPF,SDK令人费解 我查阅了各种参考资料(包括OPC UA SDK和WPF工具包),并拼凑了自己的方法来配置ITransportChannel对象以传递给OPC.UaSessionClient构造函数 我面临的问题是,为了获得与服务器预期值匹配的端点描述和配置,我使用ConfiguredEndpoint.UpdateFromServer,但在关闭其Discovery

我的C#应用程序使用OPC UA核心堆栈作为客户端,与作为服务器运行的PLC连接。我没有使用OPC UA SDK,因为应用程序是WPF,SDK令人费解

我查阅了各种参考资料(包括OPC UA SDK和WPF工具包),并拼凑了自己的方法来配置
ITransportChannel
对象以传递给
OPC.UaSessionClient
构造函数

我面临的问题是,为了获得与服务器预期值匹配的端点描述和配置,我使用
ConfiguredEndpoint.UpdateFromServer
,但在关闭其
DiscoveryClient
对象时,这会引发
ServiceResultException(BadSecureChannelClosed)

我没有看到SDK附带的
SimpleOpClient
项目报告此异常(这一点都不简单)

你知道这个函数有什么问题吗

    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);
    }

是服务器返回了
BadSecureChannelClosed
结果吗?若然,原因为何?或者它是堆栈抛出的众多内部异常之一?

首先,您的代码工作正常。即使抛出该异常,它也会更新端点。每当opc.ua.core库关闭套接字时,它都是一个已处理的异常。如果在“异常设置”窗口中选择了“不在此列表中的所有公共语言运行时异常”,则可以在调试器中看到它

第二,对于我们这些使用OPC基础代码的人来说,如果参数为true,您会很高兴知道Session.Create()构造函数将自动更新端点。请参阅本文中的示例


另外,既然您找到了我原来的WPF工具包,我想邀请您使用我的新的和改进的托管在GitHub上的工具。

首先,您的代码运行良好。即使抛出该异常,它也会更新端点。每当opc.ua.core库关闭套接字时,它都是一个已处理的异常。如果在“异常设置”窗口中选择了“不在此列表中的所有公共语言运行时异常”,则可以在调试器中看到它

第二,对于我们这些使用OPC基础代码的人来说,如果参数为true,您会很高兴知道Session.Create()构造函数将自动更新端点。请参阅本文中的示例


另外,由于您找到了我的原始WPF工具包,我想邀请您使用我的新的和改进的托管在GitHub上的工具包。

新工具包看起来很棒,如果我的应用程序需要重要的功能,我将非常乐意使用它。最初的一个对我来说非常有用,它可以帮助我了解SDK的哪些部分是必需的,哪些部分可能会丢失。我的应用程序只需要几个函数(一旦会话打开):它每秒最多读取40次八个
Int16
整数数组,每秒轮询一次心跳作为“滴答计数器”,偶尔编写一个
布尔值
,以启用远程过程调用。这使得90%的SDK是冗余的。我拼凑了一个非常简单的客户端,只使用了大约2000行代码中的OPC UA核心。SDK和堆栈(与您的工具包相反)最大的问题之一是它们似乎使用异常作为返回错误条件的机制。实际上,它们中很少有一部分似乎表明某些内容已变得不可用,因此客户机代码中充斥着
try…catch
块,这些块除了忽略异常之外基本上什么也不做。“如果参数为true”。哪个参数
updateBeforeConnect
?新工具包看起来很棒,如果我的应用程序需要一个重要的功能部分,我会非常乐意使用它。最初的一个对我来说非常有用,它可以帮助我了解SDK的哪些部分是必需的,哪些部分可能会丢失。我的应用程序只需要几个函数(一旦会话打开):它每秒最多读取40次八个
Int16
整数数组,每秒轮询一次心跳作为“滴答计数器”,偶尔编写一个
布尔值
,以启用远程过程调用。这使得90%的SDK是冗余的。我拼凑了一个非常简单的客户端,只使用了大约2000行代码中的OPC UA核心。SDK和堆栈(与您的工具包相反)最大的问题之一是它们似乎使用异常作为返回错误条件的机制。实际上,它们中很少有一部分似乎表明某些内容已变得不可用,因此客户机代码中充斥着
try…catch
块,这些块除了忽略异常之外基本上什么也不做。“如果参数为true”。哪个参数<代码>更新预测连接?