/// <summary> /// If no existing instance is passed in, creates a new instance of the type T and populates its matching property values with each <see cref="Validatable{T}"/> object in the group of <see cref="Validatables"/>. /// </summary> /// <typeparam name="T">The type of the class to be instantiated and populated.</typeparam> /// <param name="validatableGroup">The group of <see cref="Validatable{T}"/> objects whose Values to use to populate the class instance.</param> /// <param name="model">Optionally pass in an existing class instance to update.</param> /// <returns>Class of type T with the property values set based on the <see cref="Validatables"/>.</returns> public static T Populate <T>(this Validatables validatableGroup, T model = null) where T : class, new() { var instance = model ?? new T(); var instanceType = instance.GetType(); var validatableType = typeof(Validatable <>); foreach (var obj in validatableGroup.Objects) { var prop = instanceType.GetProperty(obj.ClassPropertyName); if (prop == null) { continue; } var validatable = validatableType.MakeGenericType(prop.PropertyType); var valProp = validatable.GetProperty("Value"); if (valProp != null) { prop.SetValue(instance, valProp.GetValue(obj), null); } } return(instance); }
/// <summary> /// Takes a validation result and splits it into individual results for each <see cref="Validatable{T}"/> object. /// </summary> /// <param name="valResult">The original Fluent <see cref="ValidationResult"/> from a class instance comprised of the values of the individual <see cref="Validatable{T}"/> object properties.</param> /// <param name="validatableGroup">The <see cref="Validatable{T}"/> object properties to apply results to.</param> /// <returns>An <see cref="OverallValidationResult"/> summarizing the original results (on the entire instance) as well as any rule results that were not captured by the <see cref="Validatable{T}"/> objects.</returns> public static OverallValidationResult ApplyResultsTo(this ValidationResult valResult, Validatables validatableGroup) { var overallResult = new OverallValidationResult { IsValidOverall = valResult.IsValid, AllErrors = valResult.Errors.Select(e => e.ErrorMessage).ToList() }; validatableGroup.AreValid = true; foreach (var obj in validatableGroup.Objects) { obj.IsValid = true; var relevantFailures = valResult.Errors .Where(e => e.PropertyName == obj.ClassPropertyName).ToList(); if (!relevantFailures.Any()) { continue; } var errors = relevantFailures.Select(e => e.ErrorMessage).ToList(); obj.Errors = errors; obj.IsValid = false; validatableGroup.Errors.AddRange(errors); relevantFailures.ForEach(failure => valResult.Errors.Remove(failure)); } if (validatableGroup.Errors.Any()) { validatableGroup.AreValid = false; } overallResult.NonSplitErrors = valResult.Errors.Select(e => e.ErrorMessage).ToList(); overallResult.IsValidForNonSplitErrors = overallResult.NonSplitErrors.Count == 0; return(overallResult); }
/// <summary> /// Returns the ValidationRule objects from an <see cref="AbstractValidator{T}"/> that are relevant to the given <see cref="Validatable{T}"/> objects. /// </summary> /// <typeparam name="T">The Type of the class that the <see cref="Validatable{T}"/>object properties pertains to, and therefore is the target Type for the <see cref="AbstractValidator{T}"/>.</typeparam> /// <param name="validator">The Fluent <see cref="AbstractValidator{T}"/> instance.</param> /// <param name="validatableGroup">The <see cref="Validatable{T}"/> objects for which to retrieve ValidationRules for.</param> /// <returns>A List of IValidationRule relevant to the <see cref="Validatable{T}"/> objects.</returns> public static List <IValidationRule> GetRulesFor <T>(this AbstractValidator <T> validator, Validatables validatableGroup) { var descriptor = validator.CreateDescriptor(); var rules = new List <IValidationRule>(); foreach (var obj in validatableGroup.Objects) { rules.AddRange(descriptor.GetRulesForMember(obj.ClassPropertyName)); } return(rules); }