public void Check() { Events.Clear(_modelErrors); var name = CfgMetadataCache.NormalizeName(Type, Type.Name); var node = new ObjectNode(this, name); Process(node, name, Serializer, Events, new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase), Customizers, 0, Enabled); }
protected internal void ValidateListsBasedOnAttributes(string parent) { var metadata = CfgMetadataCache.GetMetadata(Type); var elementNames = CfgMetadataCache.ElementNames(Type).ToList(); foreach (var listName in elementNames) { var listMetadata = metadata[listName]; var list = (IList)listMetadata.Getter(this); ValidateUniqueAndRequiredProperties(parent, listName, listMetadata, list); } }
void ValidateUniqueAndRequiredProperties( string parent, string listName, CfgMetadata listMetadata, ICollection list ) { //if more than one then uniqueness comes into question if (list.Count > 1) { lock (Locker) { if (listMetadata.UniquePropertiesInList == null) { listMetadata.UniquePropertiesInList = CfgMetadataCache.GetMetadata(listMetadata.ListType) .Where(p => p.Value.Attribute.unique) .Select(p => p.Key) .ToArray(); } } if (listMetadata.UniquePropertiesInList.Length <= 0) { return; } for (var j = 0; j < listMetadata.UniquePropertiesInList.Length; j++) { var unique = listMetadata.UniquePropertiesInList[j]; var duplicates = list .Cast <CfgNode>() .Where(n => n.UniqueProperties.ContainsKey(unique)) .Select(n => n.UniqueProperties[unique]) .GroupBy(n => n) .Where(group => @group.Count() > 1) .Select(group => @group.Key) .ToArray(); for (var l = 0; l < duplicates.Length; l++) { Events.DuplicateSet(unique, duplicates[l], listName); } } } else if (list.Count == 0 && listMetadata.Attribute.required) { Events.MissingRequiredAdd(parent, listName); } }
internal void ValidateBasedOnAttributes(INode node, IDictionary <string, string> parameters) { var metadata = CfgMetadataCache.GetMetadata(Type); var keys = CfgMetadataCache.PropertyNames(Type).ToArray(); if (!keys.Any()) { return; } for (var i = 0; i < keys.Length; i++) { var key = keys[i]; var item = metadata[key]; var objectValue = item.Getter(this); if (objectValue == null) { continue; } var stringValue = item.PropertyInfo.PropertyType == typeof(string) ? (string)objectValue : objectValue.ToString(); if (item.Attribute.unique) { UniqueProperties[key] = stringValue; } if (item.Attribute.DomainSet) { if (!item.IsInDomain(stringValue)) { Events.ValueNotInDomain(key, stringValue, item.Attribute.domain.Replace(item.Attribute.delimiter.ToString(), ", ")); } } CheckValueLength(item.Attribute, key, stringValue); CheckValueBoundaries(item.Attribute, key, objectValue); CheckValueMatchesRegex(item, key, stringValue); } }
/// <summary> /// Clears Cfg decorated properties. /// </summary> private void Clear() { var metadata = CfgMetadataCache.GetMetadata(GetType()); foreach (var pair in metadata) { foreach (var error in pair.Value.Errors) { _modelErrors.Add(error); } if (pair.Value.ListType == null) { pair.Value.Setter(this, pair.Value.TypeMismatch ? pair.Value.TypeDefault : pair.Value.Attribute.value); } else { pair.Value.Setter(this, pair.Value.ListActivator()); } } }
private void LoadProperties(INode node, string parentName, IDictionary <string, string> parameters, IList <ICustomizer> customizers) { var metadata = CfgMetadataCache.GetMetadata(Type); var keys = CfgMetadataCache.PropertyNames(Type).ToArray(); if (!keys.Any()) { return; } var keyHits = new HashSet <string>(); var nullWarnings = new HashSet <string>(); // first pass, set default values and report invalid attributes foreach (var attribute in node.Attributes) { var attributeKey = CfgMetadataCache.NormalizeName(Type, attribute.Name); if (metadata.ContainsKey(attributeKey)) { var item = metadata[attributeKey]; if (attribute.Value != null) { continue; } // if attribute is null, use the getter var maybe = item.Getter(this); if (maybe == null) { if (nullWarnings.Add(attribute.Name)) { Events.Warning($"'{attribute.Name}' in '{parentName}' is susceptible to nulls."); } continue; } attribute.Value = maybe; } else { if (attributeKey != "sequence") { Events.InvalidAttribute(parentName, node.Name, attribute.Name, string.Join(", ", keys)); } } } foreach (var customizer in customizers) { try { customizer.Customize(parentName, node, parameters, Events.Logger); } catch (Exception ex) { Events.Error($"{customizer.GetType().Name} error: {ex.Message}"); } } // second pass, after customizers, adjust case and trim, set property value foreach (var attribute in node.Attributes) { var attributeKey = CfgMetadataCache.NormalizeName(Type, attribute.Name); if (metadata.ContainsKey(attributeKey)) { var item = metadata[attributeKey]; if (item.PropertyInfo.PropertyType == typeof(string)) { if (attribute.Value == null) // user has not provided a default { continue; } var stringValue = attribute.Value.ToString(); if (Enabled) { if (item.Attribute.toLower) { stringValue = stringValue.ToLower(); } else if (item.Attribute.toUpper) { stringValue = stringValue.ToUpper(); } if (item.Attribute.trim || item.Attribute.trimStart && item.Attribute.trimEnd) { stringValue = stringValue.Trim(); } else { if (item.Attribute.trimStart) { stringValue = stringValue.TrimStart(); } if (item.Attribute.trimEnd) { stringValue = stringValue.TrimEnd(); } } } attribute.Value = stringValue; item.Setter(this, attribute.Value); keyHits.Add(attributeKey); } else { try { item.Setter(this, CfgConstants.Converter[item.PropertyInfo.PropertyType](attribute.Value)); keyHits.Add(attributeKey); } catch (Exception ex) { Events.SettingValue(attribute.Name, attribute.Value, parentName, node.Name, ex.Message); } } } } // missing any required attributes? if (Enabled) { foreach (var key in keys.Except(keyHits)) { var item = metadata[key]; if (item.Attribute.required) { Events.MissingAttribute(parentName, node.Name, key); } } } }
void LoadCollections(INode node, string parentName, IDictionary <string, string> parameters, uint sequence) { var metadata = CfgMetadataCache.GetMetadata(Type); var elementNames = CfgMetadataCache.ElementNames(Type).ToList(); var elements = new Dictionary <string, IList>(); var elementHits = new HashSet <string>(); var addHits = new HashSet <string>(); //initialize all the lists for (var i = 0; i < elementNames.Count; i++) { var key = elementNames[i]; elements.Add(key, (IList)metadata[key].Getter(this)); } for (var i = 0; i < node.SubNodes.Count; i++) { var subNode = node.SubNodes[i]; var subNodeKey = CfgMetadataCache.NormalizeName(Type, subNode.Name); if (metadata.ContainsKey(subNodeKey)) { elementHits.Add(subNodeKey); var item = metadata[subNodeKey]; for (var j = 0; j < subNode.SubNodes.Count; j++) { var add = subNode.SubNodes[j]; if (add.Name.Equals("add", StringComparison.Ordinal)) { var addKey = CfgMetadataCache.NormalizeName(Type, subNode.Name); addHits.Add(addKey); if (item.Loader == null) { if (item.ImplementsProperties) { object obj = null; //todo: these activator.createinstances should be cached foreach (var cp in item.Constructors) { if (!cp.Any()) { obj = Activator.CreateInstance(item.ListType); break; } if (cp.Count() == 1) { if (cp.First().ParameterType == typeof(int)) { obj = Activator.CreateInstance(item.ListType, add.Attributes.Count); break; } if (cp.First().ParameterType == typeof(string[])) { var names = add.Attributes.Select(a => a.Name).ToArray(); obj = Activator.CreateInstance(item.ListType, new object[] { names }); break; } } } if (obj == null) { Events.ConstructorNotFound(parentName, subNode.Name); } else { var properties = (IProperties)obj; for (var k = 0; k < add.Attributes.Count; k++) { foreach (var c in Customizers) { c.Customize(string.Empty, add, parameters, Events.Logger); } var attribute = add.Attributes[k]; properties[attribute.Name] = attribute.Value; } elements[addKey].Add(obj); } } } else { elements[addKey].Add(item.Loader().Process(add, subNode.Name, Serializer, Events, parameters, Customizers, ++sequence, Enabled)); } } else { Events.UnexpectedElement(add.Name, subNode.Name); } } } else { Events.InvalidElement(parentName, node.Name, subNode.Name); } } }