/// <summary> /// Recursively validates <paramref name="entity"/> by traversing all of its properties /// </summary> /// <param name="entity">The object to validate</param> /// <param name="parentContext">The rule context of the object that <paramref name="entity"/> belongs to</param> /// <param name="rules">The set of rules from the parent object to apply to <paramref name="entity"/></param> /// <param name="traverseProperties">Whether or not to traverse this <paramref name="entity"/>'s properties</param> /// <returns></returns> private IEnumerable <LogMessage> RecursiveValidate(object entity, ObjectPath entityPath, RuleContext parentContext, IEnumerable <Rule> rules, bool traverseProperties = true) { var messages = Enumerable.Empty <LogMessage>(); if (entity == null) { return(messages); } // Ensure that the rules can be re-enumerated without re-evaluating the enumeration. var collectionRules = rules.ReEnumerable(); var list = entity as IList; var dictionary = entity as IDictionary; if (traverseProperties && list != null) { // Recursively validate each list item and add the // item index to the location of each validation message var listMessages = list.SelectMany((item, index) => RecursiveValidate(item, entityPath.AppendIndex(index), parentContext.CreateChild(item, index), collectionRules)); messages = messages.Concat(listMessages); } else if (traverseProperties && dictionary != null) { // Dictionaries that don't provide any type info cannot be traversed, since it result in infinite iteration var shouldTraverseEntries = dictionary.IsTraversableDictionary(); // Recursively validate each dictionary entry and add the entry // key to the location of each validation message var dictMessages = dictionary.SelectMany((key, value) => RecursiveValidate(value, entityPath.AppendProperty((string)key), parentContext.CreateChild(value, (string)key), collectionRules, shouldTraverseEntries)); messages = messages.Concat(dictMessages); } // If this is a class, validate its value and its properties. else if (traverseProperties && entity.GetType().IsClass() && entity.GetType() != typeof(string)) { // Validate each property of the object var propertyMessages = entity.GetValidatableProperties() .SelectMany(p => ValidateProperty(p, p.GetValue(entity), entityPath.AppendProperty(p.Name), parentContext)); messages = messages.Concat(propertyMessages); } // Validate the value of the object itself var valueMessages = ValidateObjectValue(entity, collectionRules, parentContext); return(messages.Concat(valueMessages)); }
public void PushIndex(int index) { _path.Push(Path.AppendIndex(index)); }