/// <summary> /// Merges the specified messages. /// </summary> /// <param name="validationSource">The validation source.</param> /// <param name="propertyName">Name of the property.</param> /// <returns> /// The merged message. /// </returns> public MergedValidationMessage Merge(IValidatable validationSource, string propertyName = null) { validationSource.CannotBeNull(); ValidationMessageCollection messages = new ValidationMessageCollection(); if (propertyName == null) { foreach (var validationMessage in this) { if (validationMessage.ValidationSource == validationSource) { messages.Add(validationMessage); } } } else { foreach (var validationMessage in this) { if (validationMessage.ValidationSource == validationSource && validationMessage.PropertyName == propertyName) { messages.Add(validationMessage); } } } return(Merge(messages)); }
/// <summary> /// Inserts avalidation message at the specified index. /// </summary> /// <param name="index">The index.</param> /// <param name="message">The message.</param> public new void Insert(int index, ValidationMessage message) { index.MustBeBetween(0, this.Count); message.CannotBeNull(); ValidationMessageCollection messages = this[message.ValidationSource, message.PropertyName, message.ValidationContext]; if (messages != null && messages.Count > 0) { // insert only if there are no messages with higher validation level for this property if (!messages.Any(x => x.ValidationLevel > message.ValidationLevel)) { // remove messages with lower priority foreach (var lowerPriorityMessage in messages.Where(x => x.ValidationLevel < message.ValidationLevel)) { this.Remove(lowerPriorityMessage); } // insert message base.Insert(Math.Min(this.Count, index), message); } } else { base.Insert(index, message); } }
/// <summary> /// Initializes a new instance of the <see cref="ValidationException" /> class. /// </summary> /// <param name="validationMessages">The validation messages.</param> public ValidationException(ValidationMessageCollection validationMessages) : this() { validationMessages.CannotBeNull(); this.ValidaitonMessages = validationMessages; }
/// <summary> /// Validates the specified property of the specified validation source. /// </summary> /// <param name="validationSource">The validation source.</param> /// <param name="propertyName">Name of the property.</param> /// <returns>The collection of validation mesasges.</returns> public static ValidationMessageCollection Validate(this IValidatable validationSource, string propertyName) { validationSource.CannotBeNull(); propertyName.CannotBeNullOrEmpty(); ValidationMessageCollection messages = new ValidationMessageCollection(); List <string> validationContexts; object propertyValue; // get property value var properties = ReflectionExtensions.GetProperties(validationSource.GetType()); if (properties.TryGetValue(propertyName, out PropertyData propertyData)) { if (propertyData.PropertyInfo.CanRead && propertyData.PropertyInfo.CanWrite) { propertyValue = propertyData.PropertyInfo.GetValue(validationSource); // get validation context validationContexts = new List <string>(); validationContexts.Add(ValidationContext.Default); // always add the default validation context validationContexts.AddRange(validationSource.GetActiveValidationContexts() ?? Array.Empty <string>()); // add currently active validation context foreach (var validationContext in validationContexts.Distinct()) { messages.AddRange(validationSource.Validate(propertyName, propertyValue, validationContext)); } } } return(messages); }
/// <summary> /// Validates the the specified validation source. /// </summary> /// <param name="validationSource">The validation source.</param> /// <returns> /// The collection of validation mesasges. /// </returns> public static ValidationMessageCollection Validate(this IValidatable validationSource) { validationSource.CannotBeNull(); ValidationMessageCollection messages = new ValidationMessageCollection(); var propertyNames = ReflectionExtensions.GetProperties(validationSource.GetType()).Keys; foreach (var propertyName in propertyNames) { messages.AddRange(validationSource.Validate(propertyName)); } return(messages); }
/// <summary> /// Merges the specified messages. /// </summary> /// <param name="list">The validation message list.</param> /// <returns>Merged message.</returns> private static MergedValidationMessage Merge(ValidationMessageCollection list) { ValidationLevel validationLevel; int validationPriortiy = int.MaxValue; HashSet <string> messages = new HashSet <string>(); if (list == null || list.Count == 0) { validationLevel = ValidationLevel.None; } else if (list.Count == 1) { messages.Add(list[0].Message); validationLevel = list[0].ValidationLevel; } else { validationLevel = ValidationLevel.None; // find max validation level foreach (ValidationMessage vm in list) { validationLevel = (int)vm.ValidationLevel > (int)validationLevel ? vm.ValidationLevel : validationLevel; } // find max validation priority foreach (ValidationMessage vm in list.Where(x => x.ValidationLevel == validationLevel)) { validationPriortiy = vm.ValidationPriority < validationPriortiy ? vm.ValidationPriority : validationPriortiy; } // select only messages for that level foreach (ValidationMessage vm in list.Where(x => x.ValidationLevel == validationLevel && x.ValidationPriority == validationPriortiy)) { if (!messages.Contains(vm.Message)) { // prevent duplicates messages.Add(vm.Message); } } } return(new MergedValidationMessage(validationLevel, messages)); }
/// <summary> /// Validates the specified property of the specified validation source for the specified property value in specified validation context by using validation attributes. /// </summary> /// <param name="validationSource">The validation source.</param> /// <param name="propertyName">The property name.</param> /// <param name="propertyValue">The property value.</param> /// <param name="validationContext">The validation context.</param> /// <returns> /// The collection of validation mesasges. /// </returns> public static ValidationMessageCollection ValidateAttributes(this IValidatable validationSource, string propertyName, object propertyValue, string validationContext) { validationSource.CannotBeNull(); propertyName.CannotBeNullOrEmpty(); ValidationMessageCollection messages = new ValidationMessageCollection(); var validationAttributes = ReflectionExtensions.GetProperties(validationSource.GetType())[propertyName].ValidationAttributes; bool isValid; // perform attribute based validation foreach (var validationAttribute in validationAttributes) { // only matching validation context gets validated if (validationAttribute.ValidationContext == validationContext) { // custom validators might cause exceptions that are hard to find try { isValid = validationAttribute.IsValid(propertyValue); } catch (Exception ex) { throw new ValidationErrorException("Unhandled validation exception occurred.", validationAttribute.GetType(), validationSource.GetType(), propertyName, ex); } if (!isValid) { var messageKey = validationAttribute.MessageKey ?? validationAttribute.GetDefaultMessageKey() ?? "UndefinedMessageKey"; var message = validationAttribute.Message ?? validationAttribute.GetDefaultMessage() ?? "Undefined message."; var messageParameters = validationAttribute.MessageParameters; var validationLevel = validationAttribute.ValidationLevel; var validationPriority = validationAttribute.ValidationPriority; // value is invalid -> add it to the list messages.Add(new ValidationMessage(messageKey, message, messageParameters, validationSource, propertyName, validationLevel, validationContext, validationPriority)); } } } return(messages); }