/// <summary> /// Add an enum type defined in a binary schema dictionary. /// </summary> private void AddEnumTypes( IComplexTypeBuilder complexTypeBuilder, IList <Opc.Ua.Schema.Binary.TypeDescription> enumList, IList <INode> enumerationTypes ) { foreach (var item in enumList) { Type newType = null; DataTypeNode enumType = enumerationTypes.Where(node => node.BrowseName.Name == item.Name && (node.NodeId.NamespaceIndex == complexTypeBuilder.TargetNamespaceIndex || complexTypeBuilder.TargetNamespaceIndex == -1)).FirstOrDefault() as DataTypeNode; if (enumType != null) { // try dictionary enum definition var enumeratedObject = item as Schema.Binary.EnumeratedType; if (enumeratedObject != null) { // 1. use Dictionary entry newType = complexTypeBuilder.AddEnumType(enumeratedObject); } if (newType == null) { var dataType = m_session.NodeCache.Find(enumType.NodeId) as DataTypeNode; if (dataType != null) { if (dataType.DataTypeDefinition != null) { // 2. use DataTypeDefinition newType = complexTypeBuilder.AddEnumType(enumType.BrowseName.Name, dataType.DataTypeDefinition); } else { // browse for EnumFields or EnumStrings property var property = BrowseForSingleProperty(enumType.NodeId); var enumArray = m_session.ReadValue( ExpandedNodeId.ToNodeId(property.NodeId, m_session.NamespaceUris)); if (enumArray.Value is ExtensionObject[]) { // 3. use EnumValues newType = complexTypeBuilder.AddEnumType(enumType.BrowseName.Name, (ExtensionObject[])enumArray.Value); } else if (enumArray.Value is LocalizedText[]) { // 4. use EnumStrings newType = complexTypeBuilder.AddEnumType(enumType.BrowseName.Name, (LocalizedText[])enumArray.Value); } } } } if (newType != null) { // match namespace and add to type factory AddEncodeableType(enumType.NodeId, newType); } } } }
// PUBLIC METHODS /////////////////////////////////////////////////// #region Extension Methods public static IAttributeInfoBuilder Attribute <TComplex, TProperty>(this IComplexTypeBuilder <TComplex> complexTypeBuilder, Expression <Func <TComplex, TProperty> > clrPropertySelector) { Contract.Requires(complexTypeBuilder != null); Contract.Requires(clrPropertySelector != null); var clrPropertyType = typeof(TProperty); var clrPropertyName = StaticReflection.GetMemberName(clrPropertySelector); return(complexTypeBuilder.Attribute(clrPropertyName, clrPropertyType)); }
private static void AttributePropertyDiscovered(IComplexTypeBuilder complexTypeConfiguration, PropertyInfo attributeProperty) { Contract.Requires(complexTypeConfiguration != null); Contract.Requires(attributeProperty != null); var clrPropertyName = attributeProperty.Name; var clrPropertyType = attributeProperty.PropertyType; complexTypeConfiguration.Attribute(clrPropertyName, clrPropertyType); }
/// <summary> /// Load all custom types with DataTypeDefinition into the type factory. /// </summary> /// <returns>true if all types were loaded, false otherwise</returns> private IList<INode> LoadBaseEnumDataTypes( IList<INode> serverEnumTypes ) { // strip known types serverEnumTypes = RemoveKnownTypes(serverEnumTypes); // add new enum Types for all namespaces var enumTypesToDoList = new List<INode>(); int namespaceCount = m_session.NamespaceUris.Count; // create enumeration types for all namespaces for (uint i = 0; i < namespaceCount; i++) { IComplexTypeBuilder complexTypeBuilder = null; var enumTypes = serverEnumTypes.Where(node => node.NodeId.NamespaceIndex == i).ToList(); if (enumTypes.Count != 0) { if (complexTypeBuilder == null) { string targetNamespace = m_session.NamespaceUris.GetString(i); complexTypeBuilder = m_complexTypeBuilderFactory.Create( targetNamespace, (int)i); } foreach (var enumType in enumTypes) { var newType = AddEnumType(complexTypeBuilder, enumType as DataTypeNode); if (newType != null) { // match namespace and add to type factory AddEncodeableType(enumType.NodeId, newType); } else { enumTypesToDoList.Add(enumType); } } } } // all types loaded, return remaining return enumTypesToDoList; }
/// <summary> /// Add structured type to assembly with StructureDefinition. /// </summary> private Type AddStructuredType( IComplexTypeBuilder complexTypeBuilder, StructureDefinition structureDefinition, string typeName, ExpandedNodeId complexTypeId, ExpandedNodeId binaryEncodingId, ExpandedNodeId xmlEncodingId = null ) { // check all types var typeList = new List <Type>(); foreach (StructureField field in structureDefinition.Fields) { var newType = GetFieldType(field); if (newType == null) { // missing that type return(null); } typeList.Add(newType); } var fieldBuilder = complexTypeBuilder.AddStructuredType( typeName, structureDefinition ); fieldBuilder.AddTypeIdAttribute(complexTypeId, binaryEncodingId, xmlEncodingId); int order = 1; var typeListEnumerator = typeList.GetEnumerator(); foreach (StructureField field in structureDefinition.Fields) { typeListEnumerator.MoveNext(); fieldBuilder.AddField(field, typeListEnumerator.Current, order); order += 1; } return(fieldBuilder.CreateType()); }
// PUBLIC METHODS /////////////////////////////////////////////////// #region IComplexTypeConvention Implementation public IComplexTypeBuilder Apply(IComplexTypeBuilder complexTypeConfiguration) { Contract.Requires(complexTypeConfiguration != null); // Use reflection, get all the directly declard, public, and instance-based type of properties for the given resource type. var clrComplexType = complexTypeConfiguration.ClrType; var clrProperties = clrComplexType .GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance) .ToList(); // Remaining properties are attributes. var attributeProperties = DiscoverAttributeProperties(clrProperties); foreach (var attributeProperty in attributeProperties) { AttributePropertyDiscovered(complexTypeConfiguration, attributeProperty); } return(complexTypeConfiguration); }
/// <summary> /// Add an enum type defined in a DataType node. /// </summary> private Type AddEnumType( IComplexTypeBuilder complexTypeBuilder, DataTypeNode enumTypeNode ) { Type newType = null; if (enumTypeNode != null) { string name = enumTypeNode.BrowseName.Name; if (enumTypeNode.DataTypeDefinition != null) { // 1. use DataTypeDefinition newType = complexTypeBuilder.AddEnumType(name, enumTypeNode.DataTypeDefinition); } else { // browse for EnumFields or EnumStrings property var property = BrowseForSingleProperty(enumTypeNode.NodeId); if (property != null) { var enumArray = m_session.ReadValue( ExpandedNodeId.ToNodeId(property.NodeId, m_session.NamespaceUris)); if (enumArray.Value is ExtensionObject[]) { // 2. use EnumValues newType = complexTypeBuilder.AddEnumType(name, (ExtensionObject[])enumArray.Value); } else if (enumArray.Value is LocalizedText[]) { // 3. use EnumStrings newType = complexTypeBuilder.AddEnumType(name, (LocalizedText[])enumArray.Value); } } } } return(newType); }
/// <summary> /// Load all structure custom types with DataTypeDefinition into the type factory. /// </summary> /// <returns>true if all types were loaded, false otherwise</returns> private IList<INode> LoadBaseStructureDataTypes( IList<INode> serverStructTypes ) { // strip known types serverStructTypes = RemoveKnownTypes(serverStructTypes); // add new enum Types for all namespaces int namespaceCount = m_session.NamespaceUris.Count; bool retryAddStructType; var structTypesToDoList = new List<INode>(); var structTypesWorkList = serverStructTypes; // create structured types for all namespaces do { retryAddStructType = false; for (uint i = 0; i < namespaceCount; i++) { IComplexTypeBuilder complexTypeBuilder = null; var structTypes = structTypesWorkList.Where(node => node.NodeId.NamespaceIndex == i).ToList(); if (structTypes.Count != 0) { if (complexTypeBuilder == null) { string targetNamespace = m_session.NamespaceUris.GetString(i); complexTypeBuilder = m_complexTypeBuilderFactory.Create( targetNamespace, (int)i); } foreach (INode structType in structTypes) { Type newType = null; if (!(structType is DataTypeNode dataTypeNode)) { continue; } var structureDefinition = GetStructureDefinition(dataTypeNode); if (structureDefinition != null) { var encodingIds = BrowseForEncodings(structType.NodeId, m_supportedEncodings, out ExpandedNodeId binaryEncodingId, out ExpandedNodeId xmlEncodingId); try { newType = AddStructuredType( complexTypeBuilder, structureDefinition, dataTypeNode.BrowseName.Name, structType.NodeId, binaryEncodingId, xmlEncodingId ); } catch (DataTypeNotFoundException dtnfex) { var typeMatch = structTypesWorkList.Where(n => n.NodeId == dtnfex.nodeId).FirstOrDefault(); if (typeMatch == null) { throw dtnfex; } else { // known missing type, retry on next round retryAddStructType = true; } } catch { // creating the new type failed, likely a missing dependency, retry later retryAddStructType = true; } if (newType != null) { foreach (var encodingId in encodingIds) { AddEncodeableType(encodingId, newType); } AddEncodeableType(structType.NodeId, newType); } } if (newType == null) { structTypesToDoList.Add(structType); } } } } // due to type dependencies, retry missing types until there is no more progress if (retryAddStructType && structTypesWorkList.Count != structTypesToDoList.Count) { structTypesWorkList = structTypesToDoList; structTypesToDoList = new List<INode>(); } } while (retryAddStructType); // all types loaded return structTypesToDoList; }
/// <summary> /// Load all custom types with DataTypeDefinition into the type factory. /// </summary> private bool LoadBaseDataTypes( IList <INode> serverEnumTypes, IList <INode> serverStructTypes ) { // strip known types serverEnumTypes = RemoveKnownTypes(serverEnumTypes); serverStructTypes = RemoveKnownTypes(serverStructTypes); // add new enum Types for all namespaces var enumTypesToDoList = new List <INode>(); int namespaceCount = m_session.NamespaceUris.Count; // create enumeration types for all namespaces for (uint i = 0; i < namespaceCount; i++) { IComplexTypeBuilder complexTypeBuilder = null; var enumTypes = serverEnumTypes.Where(node => node.NodeId.NamespaceIndex == i).ToList(); if (enumTypes.Count != 0) { if (complexTypeBuilder == null) { string targetNamespace = m_session.NamespaceUris.GetString(i); complexTypeBuilder = m_complexTypeBuilderFactory.Create( targetNamespace, (int)i); } foreach (var enumType in enumTypes) { var newType = AddEnumType(complexTypeBuilder, enumType as DataTypeNode); if (newType != null) { // match namespace and add to type factory AddEncodeableType(enumType.NodeId, newType); } else { enumTypesToDoList.Add(enumType); } } } } bool retryAddStructType; var structTypesToDoList = new List <INode>(); var structTypesWorkList = serverStructTypes; // create structured types for all namespaces do { retryAddStructType = false; for (uint i = 0; i < namespaceCount; i++) { IComplexTypeBuilder complexTypeBuilder = null; var structTypes = structTypesWorkList.Where(node => node.NodeId.NamespaceIndex == i).ToList(); if (structTypes.Count != 0) { if (complexTypeBuilder == null) { string targetNamespace = m_session.NamespaceUris.GetString(i); complexTypeBuilder = m_complexTypeBuilderFactory.Create( targetNamespace, (int)i); } foreach (INode structType in structTypes) { Type newType = null; var dataTypeNode = structType as DataTypeNode; if (dataTypeNode == null) { continue; } var structureDefinition = dataTypeNode.DataTypeDefinition?.Body as StructureDefinition; if (structureDefinition != null) { try { newType = AddStructuredType( complexTypeBuilder, structureDefinition, dataTypeNode.BrowseName.Name, structType.NodeId, structureDefinition.DefaultEncodingId ); } catch { // creating the new type failed, likely a missing dependency, retry later retryAddStructType = true; } if (newType != null) { // match namespace and add new type to type factory AddEncodeableType(structureDefinition.DefaultEncodingId, newType); AddEncodeableType(structType.NodeId, newType); } } if (newType == null) { structTypesToDoList.Add(structType); } } } } // due to type dependencies, retry missing types until there is no more progress if (retryAddStructType && structTypesWorkList.Count != structTypesToDoList.Count) { structTypesWorkList = structTypesToDoList; structTypesToDoList = new List <INode>(); } } while (retryAddStructType); return(structTypesToDoList.Count == 0); }