diff --git a/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/ComplexTypeSystem.cs b/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/ComplexTypeSystem.cs index 5236f3a5b1..d2b8c27bcb 100644 --- a/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/ComplexTypeSystem.cs +++ b/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/ComplexTypeSystem.cs @@ -52,37 +52,6 @@ namespace Opc.Ua.Client.ComplexTypes /// public class ComplexTypeSystem { - #region Exception - public class DataTypeNotFoundException : Exception - { - public ExpandedNodeId nodeId; - public string typeName; - - public DataTypeNotFoundException(ExpandedNodeId nodeId) - { - this.nodeId = nodeId; - } - - public DataTypeNotFoundException(string typeName, string message) - : base(message) - { - this.nodeId = NodeId.Null; - this.typeName = typeName; - } - - public DataTypeNotFoundException(ExpandedNodeId nodeId, string message) - : base(message) - { - this.nodeId = nodeId; - } - - public DataTypeNotFoundException(ExpandedNodeId nodeId, string message, Exception inner) - : base(message, inner) - { - this.nodeId = nodeId; - } - } - #endregion #region Constructors /// @@ -371,6 +340,12 @@ namespace Opc.Ua.Client.ComplexTypes retryStructureList.Add(item); continue; } + catch (DataTypeNotSupportedException typeNotSupportedException) + { + Utils.Trace(typeNotSupportedException, + $"Skipped the type definition of {item.Name} because it is not supported."); + continue; + } catch (ServiceResultException sre) { Utils.Trace(sre, $"Skip the type definition of {item.Name}."); @@ -395,11 +370,19 @@ namespace Opc.Ua.Client.ComplexTypes xmlEncodingId ); } - catch (DataTypeNotFoundException) + catch (DataTypeNotFoundException typeNotFoundException) { + Utils.Trace(typeNotFoundException, + $"Skipped the type definition of {item.Name}. Retry in next round."); retryStructureList.Add(item); continue; } + catch (DataTypeNotSupportedException typeNotSupportedException) + { + Utils.Trace(typeNotSupportedException, + $"Skipped the type definition of {item.Name} because it is not supported."); + continue; + } // Add new type to factory if (complexType != null) @@ -588,13 +571,21 @@ namespace Opc.Ua.Client.ComplexTypes var typeMatch = structTypesWorkList.Where(n => n.NodeId == dtnfex.nodeId).FirstOrDefault(); if (typeMatch == null) { - throw dtnfex; + throw; } else { // known missing type, retry on next round + Utils.Trace(dtnfex, + $"Skipped the type definition of {dataTypeNode.BrowseName.Name}. Retry in next round."); retryAddStructType = true; } } + catch (DataTypeNotSupportedException dtnsex) + { + Utils.Trace(dtnsex, + $"Skipped the type definition of {dataTypeNode.BrowseName.Name} because it is not supported."); + continue; + } catch { // creating the new type failed, likely a missing dependency, retry later @@ -636,6 +627,23 @@ namespace Opc.Ua.Client.ComplexTypes { if (dataTypeNode.DataTypeDefinition?.Body is StructureDefinition structureDefinition) { + // Validate the DataTypeDefinition structure, + // but not if the type is supported + if (structureDefinition.Fields == null || + structureDefinition.BaseDataType.IsNullNodeId || + structureDefinition.BinaryEncodingId.IsNull) + { + return null; + } + foreach (var field in structureDefinition.Fields) + { + if (field.BinaryEncodingId.IsNull || + field.DataType.IsNullNodeId || + field.TypeId.IsNull) + { + return null; + } + } return structureDefinition; } return null; @@ -835,6 +843,10 @@ namespace Opc.Ua.Client.ComplexTypes serverStructTypes.Insert(0, dataTypeNode); break; } + else if (TypeInfo.GetBuiltInType(superType) != BuiltInType.Null) + { + break; + } } while (true); } @@ -918,24 +930,24 @@ namespace Opc.Ua.Client.ComplexTypes } } } - else - { - enumDescription = allEnumerationTypes.Where(node => - node.BrowseName.Name == item.Name && - (node.BrowseName.NamespaceIndex == complexTypeBuilder.TargetNamespaceIndex || - complexTypeBuilder.TargetNamespaceIndex == -1)).FirstOrDefault() - as DataTypeNode; - } - if (enumDescription != null) - { - var qName = new XmlQualifiedName(item.Name, complexTypeBuilder.TargetNamespace); - typeDictionary[qName] = enumType.NodeId; - } - if (newType != null) - { - // match namespace and add to type factory - AddEncodeableType(enumType.NodeId, newType); - } + } + else + { + enumDescription = allEnumerationTypes.Where(node => + node.BrowseName.Name == item.Name && + (node.BrowseName.NamespaceIndex == complexTypeBuilder.TargetNamespaceIndex || + complexTypeBuilder.TargetNamespaceIndex == -1)).FirstOrDefault() + as DataTypeNode; + } + if (enumDescription != null) + { + var qName = new XmlQualifiedName(item.Name, complexTypeBuilder.TargetNamespace); + typeDictionary[qName] = enumDescription.NodeId; + } + if (newType != null) + { + // match namespace and add to type factory + AddEncodeableType(enumType.NodeId, newType); } } } @@ -1044,12 +1056,32 @@ namespace Opc.Ua.Client.ComplexTypes /// private Type GetFieldType(StructureField field) { - Type fieldType = null; Type collectionType = null; + + if (field.ValueRank != ValueRanks.Scalar && + field.ValueRank != ValueRanks.OneDimension) + { + throw new DataTypeNotSupportedException(field.DataType, $"The ValueRank {field.ValueRank} is not supported."); + } + + Type fieldType = field.DataType.NamespaceIndex == 0 ? + Opc.Ua.TypeInfo.GetSystemType(field.DataType, m_session.Factory) : + GetSystemType(field.DataType); + if (fieldType == null) + { + var superType = GetBuiltInSuperType(field.DataType); + if (superType != null && + !superType.IsNullNodeId) + { + field.DataType = superType; + return GetFieldType(field); + } + return null; + } + if (field.DataType.NamespaceIndex == 0) { - fieldType = Opc.Ua.TypeInfo.GetSystemType(field.DataType, m_session.Factory); - if (field.ValueRank >= 0) + if (field.ValueRank == ValueRanks.OneDimension) { if (fieldType == typeof(Byte[])) { @@ -1069,12 +1101,7 @@ namespace Opc.Ua.Client.ComplexTypes } else { - fieldType = GetSystemType(field.DataType); - if (fieldType == null) - { - return null; - } - if (field.ValueRank >= 0) + if (field.ValueRank == ValueRanks.OneDimension) { String collectionClassName = (fieldType.Namespace != null) ? fieldType.Namespace + "." : ""; collectionClassName += fieldType.Name + "Collection, " + fieldType.Assembly; @@ -1082,7 +1109,7 @@ namespace Opc.Ua.Client.ComplexTypes } } - if (field.ValueRank >= 0) + if (field.ValueRank == ValueRanks.OneDimension) { fieldType = collectionType ?? fieldType.MakeArrayType(); } @@ -1090,6 +1117,33 @@ namespace Opc.Ua.Client.ComplexTypes return fieldType; } + /// + /// Find superType for a datatype. + /// + private NodeId GetBuiltInSuperType(NodeId dataType) + { + var superType = dataType; + do + { + superType = m_session.NodeCache.FindSuperType(superType); + if (superType == null || + superType.IsNullNodeId) + { + return null; + } + if (superType.NamespaceIndex == 0) + { + if (superType == DataTypeIds.Enumeration || + superType == DataTypeIds.Structure) + { + return null; + } + break; + } + } while (true); + return superType; + } + /// /// Split the dictionary types into a list of structures and enumerations. /// Sort the structures by dependencies, with structures with dependent @@ -1129,14 +1183,13 @@ namespace Opc.Ua.Client.ComplexTypes } } } - #endregion +#endregion - #region Private Fields +#region Private Fields private Session m_session; private IComplexTypeFactory m_complexTypeBuilderFactory; private string[] m_supportedEncodings = new string[] { BrowseNames.DefaultBinary, BrowseNames.DefaultXml, BrowseNames.DefaultJson }; private const string kOpcComplexTypesPrefix = "Opc.Ua.ComplexTypes."; - #endregion +#endregion } - }//namespace diff --git a/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/DataTypeDefinitionExtension.cs b/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/DataTypeDefinitionExtension.cs index 884356a1be..00aa267962 100644 --- a/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/DataTypeDefinitionExtension.cs +++ b/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/DataTypeDefinitionExtension.cs @@ -108,13 +108,13 @@ namespace Opc.Ua.Client.ComplexTypes // test forbidden combinations if (!isSupportedType) { - throw new ServiceResultException(StatusCodes.BadNotSupported, + throw new DataTypeNotSupportedException( "The structure definition uses a Terminator or LengthInBytes, which are not supported."); } if (isUnionType && hasBitField) { - throw new ServiceResultException(StatusCodes.BadNotSupported, + throw new DataTypeNotSupportedException( "The structure definition combines a Union and a bit filed, both of which are not supported in a single structure."); } @@ -148,7 +148,7 @@ namespace Opc.Ua.Client.ComplexTypes } else { - throw new ServiceResultException(StatusCodes.BadNotSupported, + throw new DataTypeNotSupportedException( "Options for bit selectors must be 32 bit in size, use the Int32 datatype and must be the first element in the structure."); } continue; @@ -157,7 +157,7 @@ namespace Opc.Ua.Client.ComplexTypes if (switchFieldBitPosition != 0 && switchFieldBitPosition != 32) { - throw new ServiceResultException(StatusCodes.BadNotSupported, + throw new DataTypeNotSupportedException( "Bitwise option selectors must have 32 bits."); } @@ -177,7 +177,7 @@ namespace Opc.Ua.Client.ComplexTypes var lastField = structureDefinition.Fields.Last(); if (lastField.Name != field.LengthField) { - throw new ServiceResultException(StatusCodes.BadNotSupported, + throw new DataTypeNotSupportedException( "The length field must precede the type field of an array."); } lastField.Name = field.Name; @@ -193,14 +193,14 @@ namespace Opc.Ua.Client.ComplexTypes { if (structureDefinition.Fields.Count != 0) { - throw new ServiceResultException(StatusCodes.BadNotSupported, + throw new DataTypeNotSupportedException( "The switch field of a union must be the first field in the complex type."); } continue; } if (structureDefinition.Fields.Count != dataTypeFieldPosition) { - throw new ServiceResultException(StatusCodes.BadNotSupported, + throw new DataTypeNotSupportedException( "The count of the switch field of the union member is not matching the field position."); } dataTypeFieldPosition++; @@ -213,7 +213,7 @@ namespace Opc.Ua.Client.ComplexTypes byte value; if (!switchFieldBits.TryGetValue(field.SwitchField, out value)) { - throw new ServiceResultException(StatusCodes.BadNotSupported, + throw new DataTypeNotSupportedException( $"The switch field for {field.SwitchField} does not exist."); } } @@ -261,7 +261,7 @@ namespace Opc.Ua.Client.ComplexTypes var internalField = typeof(DataTypeIds).GetField(typeName.Name); if (internalField == null) { - throw new ServiceResultException(StatusCodes.BadDataTypeIdUnknown, + throw new DataTypeNotFoundException( $"The type {typeName.Name} was not found in the internal type factory."); } return (NodeId)internalField.GetValue(typeName.Name); @@ -270,7 +270,7 @@ namespace Opc.Ua.Client.ComplexTypes { if (!typeCollection.TryGetValue(typeName, out NodeId referenceId)) { - throw new ComplexTypeSystem.DataTypeNotFoundException( + throw new DataTypeNotFoundException( typeName.Name, $"The type {typeName.Name} in namespace {typeName.Namespace} was not found."); } diff --git a/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/DataTypeException.cs b/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/DataTypeException.cs new file mode 100644 index 0000000000..390b5ca8e0 --- /dev/null +++ b/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/DataTypeException.cs @@ -0,0 +1,101 @@ +/* ======================================================================== + * Copyright (c) 2005-2019 The OPC Foundation, Inc. All rights reserved. + * + * OPC Foundation MIT License 1.00 + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * The complete license agreement can be found here: + * http://opcfoundation.org/License/MIT/1.00/ + * ======================================================================*/ + +using System; + +namespace Opc.Ua.Client.ComplexTypes +{ + + /// + /// Exception is thrown if data type is not found. + /// + public class DataTypeNotFoundException : Exception + { + public ExpandedNodeId nodeId; + public string typeName; + + public DataTypeNotFoundException(ExpandedNodeId nodeId) + { + this.nodeId = nodeId; + } + + public DataTypeNotFoundException(string typeName, string message) + : base(message) + { + this.nodeId = NodeId.Null; + this.typeName = typeName; + } + + public DataTypeNotFoundException(ExpandedNodeId nodeId, string message) + : base(message) + { + this.nodeId = nodeId; + } + + public DataTypeNotFoundException(ExpandedNodeId nodeId, string message, Exception inner) + : base(message, inner) + { + this.nodeId = nodeId; + } + } + + /// + /// DataType is not supported due to structure or value rank. + /// + public class DataTypeNotSupportedException : Exception + { + public ExpandedNodeId nodeId; + public string typeName; + + public DataTypeNotSupportedException(ExpandedNodeId nodeId) + { + this.nodeId = nodeId; + } + + public DataTypeNotSupportedException(string typeName, string message) + : base(message) + { + this.nodeId = NodeId.Null; + this.typeName = typeName; + } + + public DataTypeNotSupportedException(ExpandedNodeId nodeId, string message) + : base(message) + { + this.nodeId = nodeId; + } + + public DataTypeNotSupportedException(ExpandedNodeId nodeId, string message, Exception inner) + : base(message, inner) + { + this.nodeId = nodeId; + } + } + +}//namespace diff --git a/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/Types/BaseComplexType.cs b/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/Types/BaseComplexType.cs index 43794f8f7e..449fbf7f1c 100644 --- a/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/Types/BaseComplexType.cs +++ b/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/Types/BaseComplexType.cs @@ -95,7 +95,7 @@ namespace Opc.Ua.Client.ComplexTypes public ExpandedNodeId XmlEncodingId { get; set; } /// - public StructureType StructureType => StructureType.Structure; + public virtual StructureType StructureType => StructureType.Structure; /// /// Makes a deep copy of the object. @@ -663,7 +663,7 @@ namespace Opc.Ua.Client.ComplexTypes var propertyType = property.PropertyType; if (propertyType == typeof(Boolean)) { - property.SetValue(this, decoder.ReadBoolean(property.Name)); + property.SetValue(this, decoder.ReadBoolean(name)); } else if (propertyType == typeof(SByte)) { diff --git a/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/Types/OptionalFieldsComplexType.cs b/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/Types/OptionalFieldsComplexType.cs index 06173f3035..c6fc7dc5c0 100644 --- a/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/Types/OptionalFieldsComplexType.cs +++ b/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/Types/OptionalFieldsComplexType.cs @@ -59,7 +59,7 @@ namespace Opc.Ua.Client.ComplexTypes #region Public Properties /// - new public StructureType StructureType => StructureType.StructureWithOptionalFields; + public override StructureType StructureType => StructureType.StructureWithOptionalFields; /// /// The encoding mask for the optional fields. diff --git a/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/Types/UnionComplexType.cs b/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/Types/UnionComplexType.cs index 9a0793964d..1da4abdd02 100644 --- a/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/Types/UnionComplexType.cs +++ b/SampleApplications/SDK/Opc.Ua.Client.ComplexTypes/Types/UnionComplexType.cs @@ -65,7 +65,7 @@ namespace Opc.Ua.Client.ComplexTypes public UInt32 SwitchField => m_switchField; /// - new public StructureType StructureType => StructureType.Union; + public override StructureType StructureType => StructureType.Union; /// /// Makes a deep copy of the object. diff --git a/SampleApplications/Samples/GDS/ClientCommon/GlobalDiscoveryServerClient.cs b/SampleApplications/Samples/GDS/ClientCommon/GlobalDiscoveryServerClient.cs index 86723d1c79..9cdd88bf5e 100644 --- a/SampleApplications/Samples/GDS/ClientCommon/GlobalDiscoveryServerClient.cs +++ b/SampleApplications/Samples/GDS/ClientCommon/GlobalDiscoveryServerClient.cs @@ -944,7 +944,7 @@ namespace Opc.Ua.Gds.Client { try { - if (Object.ReferenceEquals(Session.Identity, AdminCredentials)) + if (!Object.ReferenceEquals(Session.Identity, oldUser)) { Session.UpdateSession(oldUser, PreferredLocales); } diff --git a/SampleApplications/Samples/GDS/ClientCommon/ServerPushConfigurationClient.cs b/SampleApplications/Samples/GDS/ClientCommon/ServerPushConfigurationClient.cs index 6082b63bbc..b85e0cc57d 100644 --- a/SampleApplications/Samples/GDS/ClientCommon/ServerPushConfigurationClient.cs +++ b/SampleApplications/Samples/GDS/ClientCommon/ServerPushConfigurationClient.cs @@ -30,11 +30,11 @@ using System; using System.IO; -using Opc.Ua.Client; -using Opc.Ua.Configuration; +using System.Reflection; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; -using System.Reflection; +using Opc.Ua.Client; +using Opc.Ua.Configuration; namespace Opc.Ua.Gds.Client { @@ -59,7 +59,7 @@ namespace Opc.Ua.Gds.Client public NodeId DefaultHttpsGroup { get; private set; } public NodeId DefaultUserTokenGroup { get; private set; } // TODO: currently only sha256 cert is supported - public NodeId ApplicationCertificateType { get { return Opc.Ua.ObjectTypeIds.RsaSha256ApplicationCertificateType; } } + public NodeId ApplicationCertificateType => Opc.Ua.ObjectTypeIds.RsaSha256ApplicationCertificateType; /// /// Gets the application instance. @@ -67,10 +67,7 @@ namespace Opc.Ua.Gds.Client /// /// The application instance. /// - public ApplicationInstance Application - { - get { return m_application; } - } + public ApplicationInstance Application => m_application; /// /// Gets or sets the admin credentials. @@ -124,10 +121,7 @@ namespace Opc.Ua.Gds.Client /// /// true if the session is connected; otherwise, false. /// - public bool IsConnected - { - get { return m_session != null && m_session.Connected; } - } + public bool IsConnected => m_session != null && m_session.Connected; /// /// Gets the session. @@ -135,10 +129,7 @@ namespace Opc.Ua.Gds.Client /// /// The session. /// - public Session Session - { - get { return m_session; } - } + public Session Session => m_session; /// /// Gets the endpoint. @@ -253,7 +244,7 @@ namespace Opc.Ua.Gds.Client false, m_application.ApplicationName, 60000, - null, + m_adminCredentials, m_preferredLocales); m_endpoint = m_session.ConfiguredEndpoint; @@ -782,7 +773,7 @@ namespace Opc.Ua.Gds.Client { try { - if (Object.ReferenceEquals(m_session.Identity, m_adminCredentials)) + if (!Object.ReferenceEquals(m_session.Identity, oldUser)) { m_session.UpdateSession(oldUser, m_preferredLocales); } diff --git a/SampleApplications/Samples/NetCoreComplexClient/Program.cs b/SampleApplications/Samples/NetCoreComplexClient/Program.cs index 575c3c33af..5a96aafde6 100644 --- a/SampleApplications/Samples/NetCoreComplexClient/Program.cs +++ b/SampleApplications/Samples/NetCoreComplexClient/Program.cs @@ -75,18 +75,26 @@ namespace NetCoreConsoleClient int stopTimeout = Timeout.Infinite; bool autoAccept = false; bool writeComplexInt = false; - bool noloadTypes = false; + bool noTypes = false; + bool noBrowse = false; bool verbose = false; bool json = false; + bool jsonReversible = false; + string username = null; + string pw = null; Mono.Options.OptionSet options = new Mono.Options.OptionSet { { "h|help", "show this message and exit", h => showHelp = h != null }, { "a|autoaccept", "auto accept certificates (for testing only)", a => autoAccept = a != null }, { "t|timeout=", "the number of seconds until the client stops.", (int t) => stopTimeout = t }, { "w|writeint", "Read and increment all complex types with an Int32.", w => writeComplexInt = w != null}, - { "n|noloadtypes", "Load the type system dictionary from the server.", n => noloadTypes = n != null}, + { "n|notypes", "Do not load the type system dictionary from the server.", n => noTypes = n != null}, + { "b|nobrowse", "Do not browse the address space of the server.", n => noBrowse = n != null}, + { "u|username=", "Username to access server.", (string n) => username = n}, + { "p|password=", "Password to access server.", (string n) => pw = n}, { "v|verbose", "Verbose output.", v => verbose = v != null}, { "j|json", "Print custom nodes as Json.", j => json = j != null}, + { "r|reversible", "Use Json reversible encoding.", r => jsonReversible = r != null}, }; IList extraArgs = null; @@ -133,9 +141,13 @@ namespace NetCoreConsoleClient MySampleClient client = new MySampleClient(endpointURL, autoAccept, stopTimeout) { Verbose = verbose, - LoadTypeSystem = !noloadTypes, + LoadTypeSystem = !noTypes, + BrowseAdddressSpace = !noBrowse, WriteComplexInt = writeComplexInt, - PrintAsJson = json + PrintAsJson = json, + JsonReversible = jsonReversible, + Username = username, + Password = pw }; return (int)client.Run(); } @@ -143,12 +155,17 @@ namespace NetCoreConsoleClient public class MySampleClient { - const int kReconnectPeriod = 10; + public int ReconnectPeriod { get; set; } = 10; public ExitCode ExitCode { get; set; } public bool Verbose { get; set; } = false; public bool WriteComplexInt { get; set; } = false; public bool PrintAsJson { get; set; } = false; + public bool JsonReversible { get; set; } = false; public bool LoadTypeSystem { get; set; } = false; + public bool BrowseAdddressSpace { get; set; } = false; + public String Username { get; set; } + public String Password { get; set; } + public MySampleClient( string endpointURL, @@ -222,10 +239,10 @@ namespace NetCoreConsoleClient }; // load the application configuration. - ApplicationConfiguration config = await application.LoadApplicationConfiguration(false); + ApplicationConfiguration config = await application.LoadApplicationConfiguration(false).ConfigureAwait(false); // check the application certificate. - bool haveAppCertificate = await application.CheckApplicationInstanceCertificate(false, 0); + bool haveAppCertificate = await application.CheckApplicationInstanceCertificate(false, 0).ConfigureAwait(false); if (!haveAppCertificate) { throw new Exception("Application instance certificate invalid!"); @@ -254,8 +271,19 @@ namespace NetCoreConsoleClient Console.WriteLine("3 - Create a session with OPC UA server."); ExitCode = ExitCode.ErrorCreateSession; + // create the user identity + UserIdentity userIdentity; + if (String.IsNullOrEmpty(Username) && String.IsNullOrEmpty(Password)) + { + userIdentity = new UserIdentity(new AnonymousIdentityToken()); + } + else + { + userIdentity = new UserIdentity(Username, Password); + } + // create worker session - m_session = await CreateSession(config, selectedEndpoint); + m_session = await CreateSession(config, selectedEndpoint, userIdentity).ConfigureAwait(false); // register keep alive handler m_session.KeepAlive += Client_KeepAlive; @@ -265,7 +293,7 @@ namespace NetCoreConsoleClient Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); - var allVariableNodes = BrowseAllVariables(); + var allVariableNodes = BrowseAdddressSpace ? BrowseAllVariables() : new List(); var allCustomTypeVariables = allVariableNodes.Where(n => ((VariableNode)n).DataType.NamespaceIndex != 0).ToList(); stopWatch.Stop(); @@ -286,7 +314,7 @@ namespace NetCoreConsoleClient stopWatch.Start(); var complexTypeSystem = new ComplexTypeSystem(m_session); - await complexTypeSystem.Load(); + await complexTypeSystem.Load().ConfigureAwait(false); stopWatch.Stop(); @@ -369,13 +397,13 @@ namespace NetCoreConsoleClient try { Console.WriteLine($"Open session for {variableNode}:"); - testSession = await CreateSession(config, selectedEndpoint); + testSession = await CreateSession(config, selectedEndpoint, userIdentity).ConfigureAwait(false); var complexTypeSystem = new ComplexTypeSystem(testSession); NodeId dataType = variableNode.DataType; Type nullType = testSession.Factory.GetSystemType(dataType); var valueBefore = testSession.ReadValue(variableNode.NodeId); Console.WriteLine($" -- {valueBefore}"); - Type systemType = await complexTypeSystem.LoadType(dataType); + Type systemType = await complexTypeSystem.LoadType(dataType).ConfigureAwait(false); var valueAfter = testSession.ReadValue(variableNode.NodeId); Console.WriteLine($" -- {variableNode}: {systemType} {dataType}"); Console.WriteLine($" -- {valueAfter}"); @@ -505,7 +533,7 @@ namespace NetCoreConsoleClient { Console.WriteLine("--- RECONNECTING ---"); m_reconnectHandler = new SessionReconnectHandler(); - m_reconnectHandler.BeginReconnect(sender, kReconnectPeriod * 1000, Client_ReconnectComplete); + m_reconnectHandler.BeginReconnect(sender, ReconnectPeriod * 1000, Client_ReconnectComplete); } } } @@ -543,11 +571,11 @@ namespace NetCoreConsoleClient } } - private Task CreateSession(ApplicationConfiguration config, EndpointDescription selectedEndpoint) + private Task CreateSession(ApplicationConfiguration config, EndpointDescription selectedEndpoint, IUserIdentity userIdentity) { var endpointConfiguration = EndpointConfiguration.Create(config); var endpoint = new ConfiguredEndpoint(null, selectedEndpoint, endpointConfiguration); - return Session.Create(config, endpoint, false, "OPC UA Console Client", 60000, new UserIdentity(new AnonymousIdentityToken()), null); + return Session.Create(config, endpoint, false, "OPC UA Complex Types Client", 60000, userIdentity, null); } private void WriteValue(Session session, NodeId variableId, DataValue value) @@ -586,7 +614,7 @@ namespace NetCoreConsoleClient private void PrintValueAsJson(string name, DataValue value) { - var jsonEncoder = new JsonEncoder(m_session.MessageContext, false); + var jsonEncoder = new JsonEncoder(m_session.MessageContext, JsonReversible); jsonEncoder.WriteDataValue(name, value); var textbuffer = jsonEncoder.CloseAndReturnText(); // prettify @@ -611,7 +639,7 @@ namespace NetCoreConsoleClient Console.WriteLine(textbuffer); Console.WriteLine(stringWriter.ToString()); ExitCode = ExitCode.ErrorJSONDecode; - throw ex; + throw ; } } } diff --git a/Stack/Opc.Ua.Core/Security/Certificates/CertificateFactory.cs b/Stack/Opc.Ua.Core/Security/Certificates/CertificateFactory.cs index 6246670d14..0580b2598a 100644 --- a/Stack/Opc.Ua.Core/Security/Certificates/CertificateFactory.cs +++ b/Stack/Opc.Ua.Core/Security/Certificates/CertificateFactory.cs @@ -536,7 +536,11 @@ public class CertificateFactory List certCACrl = store.EnumerateCRLs(certCA, false); - var certificateCollection = new X509Certificate2Collection() { certificate }; + var certificateCollection = new X509Certificate2Collection() { }; + if (!isCACert) + { + certificateCollection.Add(certificate); + } updatedCRL = RevokeCertificate(certCAWithPrivateKey, certCACrl, certificateCollection); store.AddCRL(updatedCRL); diff --git a/Stack/Opc.Ua.Core/Stack/Https/HttpsListener.cs b/Stack/Opc.Ua.Core/Stack/Https/HttpsListener.cs index ea7c37d8d8..41e11a144d 100644 --- a/Stack/Opc.Ua.Core/Stack/Https/HttpsListener.cs +++ b/Stack/Opc.Ua.Core/Stack/Https/HttpsListener.cs @@ -177,7 +177,7 @@ namespace Opc.Ua.Bindings { Startup.Listener = this; m_hostBuilder = new WebHostBuilder(); -#if NETSTANDARD2_0 +#if NETSTANDARD2_0 || NETSTANDARD2_1 HttpsConnectionAdapterOptions httpsOptions = new HttpsConnectionAdapterOptions(); httpsOptions.CheckCertificateRevocation = false; httpsOptions.ClientCertificateMode = ClientCertificateMode.NoCertificate; diff --git a/Stack/Opc.Ua.Core/Types/Encoders/EncodableObject.cs b/Stack/Opc.Ua.Core/Types/Encoders/EncodableObject.cs index e1ba8f1806..260bcece54 100644 --- a/Stack/Opc.Ua.Core/Types/Encoders/EncodableObject.cs +++ b/Stack/Opc.Ua.Core/Types/Encoders/EncodableObject.cs @@ -67,9 +67,9 @@ namespace Opc.Ua return StatusCodes.BadDataEncodingUnsupported; } - bool useXml = dataEncoding.Name == DefaultXml; + bool useXml = dataEncoding.Name == BrowseNames.DefaultXml; - if (!useXml && dataEncoding.Name != DefaultBinary) + if (!useXml && dataEncoding.Name != BrowseNames.DefaultBinary) { return StatusCodes.BadDataEncodingInvalid; } @@ -198,16 +198,6 @@ namespace Opc.Ua encoder.WriteEncodeable(null, encodeable, null); return encoder.CloseAndReturnBuffer(); } - - /// - /// The BrowseName for the DefaultBinary component. - /// - private const string DefaultBinary = "Default Binary"; - - /// - /// The BrowseName for the DefaultXml component. - /// - private const string DefaultXml = "Default XML"; #endregion /// diff --git a/Stack/Opc.Ua.Core/Types/Schemas/BinarySchemaValidator.cs b/Stack/Opc.Ua.Core/Types/Schemas/BinarySchemaValidator.cs index 481c85dcbf..72387a349f 100644 --- a/Stack/Opc.Ua.Core/Types/Schemas/BinarySchemaValidator.cs +++ b/Stack/Opc.Ua.Core/Types/Schemas/BinarySchemaValidator.cs @@ -339,7 +339,7 @@ namespace Opc.Ua.Schema.Binary return false; } - if (!Char.IsLetter(name[0]) && name[0] != '_') + if (!Char.IsLetter(name[0]) && name[0] != '_' && name[0] != '"') { return false; } @@ -351,7 +351,7 @@ namespace Opc.Ua.Schema.Binary continue; } - if (name[ii] == '.' || name[ii] == '-' || name[ii] == '_') + if (name[ii] == '.' || name[ii] == '-' || name[ii] == '_' || name[ii] == '"') { continue; }