Hello,
I'm currently trying to validate the usability of the QuickOpc library and I have an issue.
I used the code available here: opclabs.doc-that.com/files/onlinedocs/QuickOpc/Latest/User%2....NET%20Core%20CLI%20Tools.html
It works like a charm!
Now I replaced with the server address of my client as well as the correct itemDescriptor and I get an SSL/TLS error (full stack trace at the end of the message).
I googled the error and it seems like the solution would be to give a special Handler to the HttpClient used to instruct it to ignore such errors.
However, I cannot get my hands on the client as it is constructed probably very deep in the library and there are no possibility for me to find it.
I know that SSL/TLS is a big deal and that proper certificates should always be used but in this case, the OPC server is sitting within a highly secure network only accessible through a VPN.
For information, I used Kassl dOPC Explorer and I can communicate with my server without any problem. I also tried multiple aother clients just to make sure it was not that one being too nice with me.
Did you ever faced this error and would you have a solution for this?
For reference, here is a stackoverflow post that seem to describe the TLS issue: stackoverflow.com/questions/1742938/how-to-solve-could-not-e...ip-for-the-ssl-tls-secure-chan
The strange thing is that, as you can see in the stacktrace below, the authority that seem to cause the SSL/TLS error is "localhost"
The code I use is identical as the one from the demo link I gave above with the serverDescriptor and itemDescriptor adapted to my server.
Anyway, the library seem to be awesome and seem to be exactly what I need but I am locked and won't purchase the product if I cannot validate that it works for my usecase.
Side Note: I'm writing the code on Windows using Rider but in production, it will be deployed in a Docker container on Linux, just in case it makes a difference.
And here is the full stacktrace (SSL ERROR HIGHLIGHTED):
Unhandled exception. OpcLabs.EasyOpc.OperationModel.OpcException: An OPC operation failure with error ID 'OpcLabs.EasyOpc.Engine.NetApiException' occurred, originating from 'System.
Private.CoreLib' and with depth of 6. The inner exception contains details about the problem.
---> OpcLabs.EasyOpc.Engine.NetApiException: An exception occurred during processing in a NET API OPC Data Access client. The inner exception contains details about the problem.
+ The client method called was 'ReadMultipleItemValues'.
---> OpcLabs.EasyOpc.Engine.NetApiException: An exception occurred during processing in a NET API OPC Data Access client. The inner exception contains details about the problem.
---> Opc.ResultIDException: E_FAIL
Could not establish trust relationship for the SSL/TLS secure channel with authority 'localhost'.
---> System.ServiceModel.Security.SecurityNegotiationException: Could not establish trust relationship for the SSL/TLS secure channel with authority 'localhost'.
---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
at System.Net.Security.SslStream.ThrowIfExceptional()
at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result)
at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__65_1(IAsyncResult iar)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.DecompressionHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpClientRequestChannel.HttpClientChannelAsyncRequest.SendRequestAsync(Message message, TimeoutHelper timeoutHelper)
--- End of inner exception stack trace ---
at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(HttpRequestException requestException, HttpRequestMessage request, HttpAbortReason abortReason)
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpClientRequestChannel.HttpClientChannelAsyncRequest.SendRequestAsync(Message message, TimeoutHelper timeoutHelper)
at System.ServiceModel.Channels.RequestChannel.RequestAsync(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.RequestChannel.RequestAsyncInternal(Message message, TimeSpan timeout)
at System.Runtime.TaskHelpers.WaitForCompletionNoSpin[TResult](Task`1 task)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(MethodCall methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(MethodInfo targetMethod, Object[] args)
--- End of stack trace from previous location where exception was thrown ---
at System.Reflection.DispatchProxyGenerator.Invoke(Object[] args)
at generatedProxy_1.GetStatus(GetStatusRequest )
at OpcXml.Da10.ServiceReference.ServiceClient.OpcXml.Da10.ServiceReference.Service.GetStatus(GetStatusRequest request)
at OpcXml.Da10.ServiceReference.ServiceClient.GetStatus(GetStatus GetStatus1)
at OpcXml.Da10.Service.GetStatus(String LocaleID, String ClientRequestHandle, ServerStatus& Status)
at OpcXml.Da.Server.GetStatus()
at OpcXml.Da.Server.Initialize(URL url, ConnectData connectData)
at OpcXml.Factory.CreateInstance(URL url, ConnectData connectData)
--- End of inner exception stack trace ---
at Opc.Server.Connect(URL url, ConnectData connectData)
at Opc.Da.Server.Connect(URL url, ConnectData connectData)
at Opc.Server.Connect(ConnectData connectData)
at OpcLabs.EasyOpc.Implementation.NetApi.DataAccess.NetApiOpcDaServer.ServerConnect(Server server, ConnectData connectData, Exception& exception)
--- End of inner exception stack trace ---
at OpcLabs.EasyOpc.Implementation.NetApi.DataAccess.NetApiOpcDaServer.ConnectToServer(WebProxy proxy, Server server, NetworkCredential credentials, String connectionGroupName, EasyDAAdaptableParameters adaptableParameters)
at OpcLabs.EasyOpc.Implementation.NetApi.DataAccess.NetApiOpcDaServer.Connect(Boolean doOnlyIfGoodStatus, Boolean callGetStatus, Exception& exception)
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
at OpcLabs.EasyOpc.Internal.EasyUtilities.CheckSuccess(OperationResult operationResult)
at OpcLabs.EasyOpc.DataAccess.IEasyDAClientExtension.ReadItemValue(IEasyDAClient client, ServerDescriptor serverDescriptor, DAItemDescriptor itemDescriptor, DAReadParameters readParameters)
at OpcLabs.EasyOpc.DataAccess.IEasyDAClientExtension.ReadItemValue(IEasyDAClient client, ServerDescriptor serverDescriptor, DAItemDescriptor itemDescriptor)
at HelloWorld.Program.Main(String[] args) in C:\projects\HelloWorld\HelloWorld\Program.cs:line 34
Thanks for any support you can provide.
I'm currently trying to validate the usability of the QuickOpc library and I have an issue.
I used the code available here: opclabs.doc-that.com/files/onlinedocs/QuickOpc/Latest/User%2....NET%20Core%20CLI%20Tools.html
It works like a charm!
Now I replaced with the server address of my client as well as the correct itemDescriptor and I get an SSL/TLS error (full stack trace at the end of the message).
I googled the error and it seems like the solution would be to give a special Handler to the HttpClient used to instruct it to ignore such errors.
However, I cannot get my hands on the client as it is constructed probably very deep in the library and there are no possibility for me to find it.
I know that SSL/TLS is a big deal and that proper certificates should always be used but in this case, the OPC server is sitting within a highly secure network only accessible through a VPN.
For information, I used Kassl dOPC Explorer and I can communicate with my server without any problem. I also tried multiple aother clients just to make sure it was not that one being too nice with me.
Did you ever faced this error and would you have a solution for this?
For reference, here is a stackoverflow post that seem to describe the TLS issue: stackoverflow.com/questions/1742938/how-to-solve-could-not-e...ip-for-the-ssl-tls-secure-chan
The strange thing is that, as you can see in the stacktrace below, the authority that seem to cause the SSL/TLS error is "localhost"
The code I use is identical as the one from the demo link I gave above with the serverDescriptor and itemDescriptor adapted to my server.
Anyway, the library seem to be awesome and seem to be exactly what I need but I am locked and won't purchase the product if I cannot validate that it works for my usecase.
Side Note: I'm writing the code on Windows using Rider but in production, it will be deployed in a Docker container on Linux, just in case it makes a difference.
And here is the full stacktrace (SSL ERROR HIGHLIGHTED):
Unhandled exception. OpcLabs.EasyOpc.OperationModel.OpcException: An OPC operation failure with error ID 'OpcLabs.EasyOpc.Engine.NetApiException' occurred, originating from 'System.
Private.CoreLib' and with depth of 6. The inner exception contains details about the problem.
---> OpcLabs.EasyOpc.Engine.NetApiException: An exception occurred during processing in a NET API OPC Data Access client. The inner exception contains details about the problem.
+ The client method called was 'ReadMultipleItemValues'.
---> OpcLabs.EasyOpc.Engine.NetApiException: An exception occurred during processing in a NET API OPC Data Access client. The inner exception contains details about the problem.
---> Opc.ResultIDException: E_FAIL
Could not establish trust relationship for the SSL/TLS secure channel with authority 'localhost'.
---> System.ServiceModel.Security.SecurityNegotiationException: Could not establish trust relationship for the SSL/TLS secure channel with authority 'localhost'.
---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
at System.Net.Security.SslStream.ThrowIfExceptional()
at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result)
at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__65_1(IAsyncResult iar)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.DecompressionHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpClientRequestChannel.HttpClientChannelAsyncRequest.SendRequestAsync(Message message, TimeoutHelper timeoutHelper)
--- End of inner exception stack trace ---
at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(HttpRequestException requestException, HttpRequestMessage request, HttpAbortReason abortReason)
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpClientRequestChannel.HttpClientChannelAsyncRequest.SendRequestAsync(Message message, TimeoutHelper timeoutHelper)
at System.ServiceModel.Channels.RequestChannel.RequestAsync(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.RequestChannel.RequestAsyncInternal(Message message, TimeSpan timeout)
at System.Runtime.TaskHelpers.WaitForCompletionNoSpin[TResult](Task`1 task)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(MethodCall methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(MethodInfo targetMethod, Object[] args)
--- End of stack trace from previous location where exception was thrown ---
at System.Reflection.DispatchProxyGenerator.Invoke(Object[] args)
at generatedProxy_1.GetStatus(GetStatusRequest )
at OpcXml.Da10.ServiceReference.ServiceClient.OpcXml.Da10.ServiceReference.Service.GetStatus(GetStatusRequest request)
at OpcXml.Da10.ServiceReference.ServiceClient.GetStatus(GetStatus GetStatus1)
at OpcXml.Da10.Service.GetStatus(String LocaleID, String ClientRequestHandle, ServerStatus& Status)
at OpcXml.Da.Server.GetStatus()
at OpcXml.Da.Server.Initialize(URL url, ConnectData connectData)
at OpcXml.Factory.CreateInstance(URL url, ConnectData connectData)
--- End of inner exception stack trace ---
at Opc.Server.Connect(URL url, ConnectData connectData)
at Opc.Da.Server.Connect(URL url, ConnectData connectData)
at Opc.Server.Connect(ConnectData connectData)
at OpcLabs.EasyOpc.Implementation.NetApi.DataAccess.NetApiOpcDaServer.ServerConnect(Server server, ConnectData connectData, Exception& exception)
--- End of inner exception stack trace ---
at OpcLabs.EasyOpc.Implementation.NetApi.DataAccess.NetApiOpcDaServer.ConnectToServer(WebProxy proxy, Server server, NetworkCredential credentials, String connectionGroupName, EasyDAAdaptableParameters adaptableParameters)
at OpcLabs.EasyOpc.Implementation.NetApi.DataAccess.NetApiOpcDaServer.Connect(Boolean doOnlyIfGoodStatus, Boolean callGetStatus, Exception& exception)
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
at OpcLabs.EasyOpc.Internal.EasyUtilities.CheckSuccess(OperationResult operationResult)
at OpcLabs.EasyOpc.DataAccess.IEasyDAClientExtension.ReadItemValue(IEasyDAClient client, ServerDescriptor serverDescriptor, DAItemDescriptor itemDescriptor, DAReadParameters readParameters)
at OpcLabs.EasyOpc.DataAccess.IEasyDAClientExtension.ReadItemValue(IEasyDAClient client, ServerDescriptor serverDescriptor, DAItemDescriptor itemDescriptor)
at HelloWorld.Program.Main(String[] args) in C:\projects\HelloWorld\HelloWorld\Program.cs:line 34
Thanks for any support you can provide.