private static bool ValidateInternal(object obj, string path, ValidateAttribute validation, IList <ValidationError> validationErrors) { if (ReferenceEquals(obj, null)) { if (validation.Required) { validationErrors.Add(new ValidationError(path, "Property is required, found null")); return(false); } // If object is null, we cannot do anything else. return(true); } var objType = obj.GetType(); if (AlwaysValidTypes.Contains(objType) || PortableTypeInfo.IsEnum(objType)) { return(true); } var isValueType = PortableTypeInfo.IsValueType(objType); // Check whether this type is nullable. if (validation.Required && isValueType && PortableTypeInfo.IsGenericType(objType) && objType.GetGenericTypeDefinition() == typeof(Nullable <>)) { var nullableProps = PortableTypeInfo.GetPublicProperties(objType); var nullableHasValueProp = nullableProps.First(p => p.Name == nameof(Nullable <bool> .HasValue)); if ((bool)PortableTypeInfo.GetPublicPropertyValue(obj, nullableHasValueProp)) { validationErrors.Add(new ValidationError(path, "Property is required, found null")); return(false); } var nullableValueProp = nullableProps.First(p => p.Name == nameof(Nullable <bool> .Value)); var nullableValue = PortableTypeInfo.GetPublicPropertyValue(obj, nullableValueProp); return(ValidateInternal(nullableValue, path, validation, validationErrors)); } var collection = obj as ICollection; if (collection != null) { var c = collection.Count; if (c < validation.CollectionItemsMinCount) { validationErrors.Add(new ValidationError(path, $"Minimum item count is {validation.CollectionItemsMinCount}, found {c}")); } if (c > validation.CollectionItemsMaxCount) { validationErrors.Add(new ValidationError(path, $"Maximum item count is {validation.CollectionItemsMaxCount}, found {c}")); } } var enumerable = obj as IEnumerable; if (enumerable != null && validation.Enumerable) { var itemValidation = new ValidateAttribute { Required = validation.EnumerableItemsRequired }; var index = 0; foreach (var item in enumerable) { var indexedNewPath = $"{path}[{index++}]"; ValidateInternal(item, indexedNewPath, itemValidation, validationErrors); } } if (PortableTypeInfo.IsClass(objType) || isValueType) { var props = PortableTypeInfo.GetPublicProperties(objType); var reqProps = from p in props from a in PortableTypeInfo.GetCustomAttributes(p, false) let v = a as ValidateAttribute where v != null select new { PropertyInfo = p, Validation = v }; #if !(NETSTD10 || NETSTD11) && FAST_MEMBER var typeAccessor = Reflection.FastMember.TypeAccessor.Create(objType); #endif foreach (var rp in reqProps) { var propertyInfo = rp.PropertyInfo; #if !(NETSTD10 || NETSTD11) && FAST_MEMBER var propertyValue = PortableTypeInfo.GetPublicPropertyValue(typeAccessor, obj, propertyInfo); #else var propertyValue = PortableTypeInfo.GetPublicPropertyValue(obj, propertyInfo); #endif var newPath = $"{path}.{propertyInfo.Name}"; ValidateInternal(propertyValue, newPath, rp.Validation, validationErrors); } return(validationErrors.Count == 0); } // Non dovrei mai finire qui! return(true); }
private static bool ValidateInternal(object obj, string path, ValidateAttribute validation, IList<ValidationError> validationErrors) { if (ReferenceEquals(obj, null)) { if (validation.Required) { validationErrors.Add(new ValidationError { Path = path, Reason = "Property is required, found null" }); return false; } // If object is null, we cannot do anything else. return true; } var objType = obj.GetType(); if (AlwaysValidTypes.Contains(objType) || PortableTypeInfo.IsEnum(objType)) { return true; } var isValueType = PortableTypeInfo.IsValueType(objType); // Check whether this type is nullable. if (validation.Required && isValueType && PortableTypeInfo.IsGenericType(objType) && objType.GetGenericTypeDefinition() == typeof(Nullable<>)) { var nullableProps = PortableTypeInfo.GetPublicProperties(objType); var nullableHasValueProp = nullableProps.First(p => p.Name == nameof(Nullable<bool>.HasValue)); if ((bool) PortableTypeInfo.GetPublicPropertyValue(obj, nullableHasValueProp)) { validationErrors.Add(new ValidationError { Path = path, Reason = "Property is required, found null" }); return false; } var nullableValueProp = nullableProps.First(p => p.Name == nameof(Nullable<bool>.Value)); var nullableValue = PortableTypeInfo.GetPublicPropertyValue(obj, nullableValueProp); return ValidateInternal(nullableValue, path, validation, validationErrors); } var collection = obj as ICollection; if (collection != null) { var c = collection.Count; if (c < validation.CollectionItemsMinCount) { validationErrors.Add(new ValidationError { Path = path, Reason = $"Minimum item count is {validation.CollectionItemsMinCount}, found {c}" }); } if (c > validation.CollectionItemsMaxCount) { validationErrors.Add(new ValidationError { Path = path, Reason = $"Maximum item count is {validation.CollectionItemsMaxCount}, found {c}" }); } } var enumerable = obj as IEnumerable; if (enumerable != null && validation.Enumerable) { var itemValidation = new ValidateAttribute { Required = validation.EnumerableItemsRequired }; var index = 0; foreach (var item in enumerable) { var indexedNewPath = $"{path}[{index++}]"; ValidateInternal(item, indexedNewPath, itemValidation, validationErrors); } } if (PortableTypeInfo.IsClass(objType) || isValueType) { var props = PortableTypeInfo.GetPublicProperties(objType); var reqProps = from p in props from a in PortableTypeInfo.GetCustomAttributes(p, false) let v = a as ValidateAttribute where v != null select new { PropertyInfo = p, Validation = v }; #if !(PORTABLE || NETSTD11 || NETSTD13) var typeAccessor = Reflection.FastMember.TypeAccessor.Create(objType); #endif foreach (var rp in reqProps) { var propertyInfo = rp.PropertyInfo; #if (PORTABLE || NETSTD11 || NETSTD13) var propertyValue = PortableTypeInfo.GetPublicPropertyValue(obj, propertyInfo); #else var propertyValue = PortableTypeInfo.GetPublicPropertyValue(typeAccessor, obj, propertyInfo); #endif var newPath = $"{path}.{propertyInfo.Name}"; ValidateInternal(propertyValue, newPath, rp.Validation, validationErrors); } return validationErrors.Count == 0; } // Non dovrei mai finire qui! return true; }