Browse Source

Refactored Validation package code on code review session.

pull/189/head
Halil İbrahim Kalkan 8 years ago
parent
commit
867c491009
  1. 64
      src/Volo.Abp.Validation/Volo/Abp/Validation/DataAnnotationValidator.cs
  2. 5
      src/Volo.Abp.Validation/Volo/Abp/Validation/IDataAnnotationValidator.cs
  3. 11
      src/Volo.Abp.Validation/Volo/Abp/Validation/IObjectValidator.cs
  4. 3
      src/Volo.Abp.Validation/Volo/Abp/Validation/MethodInvocationValidator.cs
  5. 42
      src/Volo.Abp.Validation/Volo/Abp/Validation/ObjectValidator.cs

64
src/Volo.Abp.Validation/Volo/Abp/Validation/DataAnnotationValidator.cs

@ -10,53 +10,61 @@ namespace Volo.Abp.Validation
{ {
public void Validate(object validatingObject) public void Validate(object validatingObject)
{ {
var validationResult = new AbpValidationResult(); var errors = GetErrors(validatingObject);
AddErrors(validationResult, validatingObject); if (errors.Any())
if (validationResult.Errors.Any())
{ {
throw new AbpValidationException( throw new AbpValidationException(
"Object state is not valid! See ValidationErrors for details.", "Object state is not valid! See ValidationErrors for details.",
validationResult.Errors errors
); );
} }
} }
/// <summary> /// <summary>
/// Checks all properties for DataAnnotations attributes. /// Gets all errors from properties for DataAnnotations attributes and IValidatableObject interface.
/// </summary> /// </summary>
public virtual void AddErrors(IAbpValidationResult validationResult, object validatingObject) public virtual List<ValidationResult> GetErrors(object validatingObject)
{ {
var errors = new List<ValidationResult>();
var properties = TypeDescriptor.GetProperties(validatingObject).Cast<PropertyDescriptor>(); var properties = TypeDescriptor.GetProperties(validatingObject).Cast<PropertyDescriptor>();
foreach (var property in properties) foreach (var property in properties)
{ {
var validationAttributes = property.Attributes.OfType<ValidationAttribute>().ToArray(); AddPropertyErrors(validatingObject, property, errors);
if (validationAttributes.IsNullOrEmpty()) }
{
continue;
}
var validationContext = new ValidationContext(validatingObject) if (validatingObject is IValidatableObject validatableObject)
{ {
DisplayName = property.DisplayName, errors.AddRange(
MemberName = property.Name validatableObject.Validate(new ValidationContext(validatableObject))
}; );
}
foreach (var attribute in validationAttributes) return errors;
{ }
var result = attribute.GetValidationResult(property.GetValue(validatingObject), validationContext);
if (result != null) protected virtual void AddPropertyErrors(object validatingObject, PropertyDescriptor property, List<ValidationResult> errors)
{ {
validationResult.Errors.Add(result); var validationAttributes = property.Attributes.OfType<ValidationAttribute>().ToArray();
} if (validationAttributes.IsNullOrEmpty())
} {
return;
} }
if (validatingObject is IValidatableObject) var validationContext = new ValidationContext(validatingObject)
{ {
var results = (validatingObject as IValidatableObject).Validate(new ValidationContext(validatingObject)); DisplayName = property.DisplayName,
validationResult.Errors.AddRange(results); MemberName = property.Name
};
foreach (var attribute in validationAttributes)
{
var result = attribute.GetValidationResult(property.GetValue(validatingObject), validationContext);
if (result != null)
{
errors.Add(result);
}
} }
} }
} }

5
src/Volo.Abp.Validation/Volo/Abp/Validation/IDataAnnotationValidator.cs

@ -1,9 +1,12 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Volo.Abp.Validation namespace Volo.Abp.Validation
{ {
public interface IDataAnnotationValidator public interface IDataAnnotationValidator
{ {
void Validate(object validatingObject); void Validate(object validatingObject);
void AddErrors(IAbpValidationResult validationResult, object validatingObject); List<ValidationResult> GetErrors(object validatingObject);
} }
} }

11
src/Volo.Abp.Validation/Volo/Abp/Validation/IObjectValidator.cs

@ -1,9 +1,16 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Volo.Abp.Validation namespace Volo.Abp.Validation
{ {
public interface IObjectValidator public interface IObjectValidator
{ {
void Validate(object validatingObject, string name = null, bool allowNull = false); void Validate(
object validatingObject,
string name = null,
bool allowNull = false
);
void AddErrors(IAbpValidationResult validationResult, object validatingObject, string name = null, bool allowNull = false); List<ValidationResult> GetErrors(object validatingObject, string name = null, bool allowNull = false);
} }
} }

3
src/Volo.Abp.Validation/Volo/Abp/Validation/MethodInvocationValidator.cs

@ -40,6 +40,7 @@ namespace Volo.Abp.Validation
throw new Exception("Method parameter count does not match with argument count!"); throw new Exception("Method parameter count does not match with argument count!");
} }
//todo: consider to remove this condition
if (context.Errors.Any() && HasSingleNullArgument(context)) if (context.Errors.Any() && HasSingleNullArgument(context))
{ {
ThrowValidationError(context); ThrowValidationError(context);
@ -90,7 +91,7 @@ namespace Volo.Abp.Validation
parameterInfo.IsOut || parameterInfo.IsOut ||
TypeHelper.IsPrimitiveExtendedIncludingNullable(parameterInfo.ParameterType, includeEnums: true); TypeHelper.IsPrimitiveExtendedIncludingNullable(parameterInfo.ParameterType, includeEnums: true);
_objectValidator.AddErrors(context, parameterValue, parameterInfo.Name, allowNulls); context.Errors.AddRange(_objectValidator.GetErrors(parameterValue, parameterInfo.Name, allowNulls));
} }
} }
} }

42
src/Volo.Abp.Validation/Volo/Abp/Validation/ObjectValidator.cs

@ -1,4 +1,5 @@
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
@ -8,7 +9,7 @@ using Volo.Abp.Reflection;
namespace Volo.Abp.Validation namespace Volo.Abp.Validation
{ {
public class ObjectValidator : ITransientDependency, IObjectValidator public class ObjectValidator : IObjectValidator, ITransientDependency
{ {
private const int MaxRecursiveParameterValidationDepth = 8; private const int MaxRecursiveParameterValidationDepth = 8;
@ -23,36 +24,38 @@ namespace Volo.Abp.Validation
public virtual void Validate(object validatingObject, string name = null, bool allowNull = false) public virtual void Validate(object validatingObject, string name = null, bool allowNull = false)
{ {
var validationResult = new AbpValidationResult(); var errors = GetErrors(validatingObject, name, allowNull);
AddErrors(validationResult, validatingObject, name, allowNull); if (errors.Any())
if (validationResult.Errors.Any())
{ {
throw new AbpValidationException( throw new AbpValidationException(
"Object state is not valid! See ValidationErrors for details.", "Object state is not valid! See ValidationErrors for details.",
validationResult.Errors errors
); );
} }
} }
public virtual void AddErrors(IAbpValidationResult validationResult, object validatingObject, string name = null, bool allowNull = false) public virtual List<ValidationResult> GetErrors(object validatingObject, string name = null, bool allowNull = false)
{ {
var errors = new List<ValidationResult>();
if (validatingObject == null && !allowNull) if (validatingObject == null && !allowNull)
{ {
validationResult.Errors.Add( errors.Add(
name == null name == null
? new ValidationResult("Given object is null!") ? new ValidationResult("Given object is null!")
: new ValidationResult(name + " is null!", new[] { name }) : new ValidationResult(name + " is null!", new[] { name })
); );
return; return errors;
} }
ValidateObjectRecursively(validationResult, validatingObject, 1); ValidateObjectRecursively(errors, validatingObject, currentDepth: 1);
return errors;
} }
protected virtual void ValidateObjectRecursively(IAbpValidationResult context, object validatingObject, int currentDepth) protected virtual void ValidateObjectRecursively(List<ValidationResult> errors, object validatingObject, int currentDepth)
{ {
if (currentDepth > MaxRecursiveParameterValidationDepth) if (currentDepth > MaxRecursiveParameterValidationDepth)
{ {
@ -64,20 +67,19 @@ namespace Volo.Abp.Validation
return; return;
} }
_dataAnnotationValidator.AddErrors(context, validatingObject); errors.AddRange(_dataAnnotationValidator.GetErrors(validatingObject));
//Validate items of enumerable //Validate items of enumerable
if (validatingObject is IEnumerable && !(validatingObject is IQueryable)) if (validatingObject is IEnumerable)
{ {
foreach (var item in (validatingObject as IEnumerable)) if (!(validatingObject is IQueryable))
{ {
ValidateObjectRecursively(context, item, currentDepth + 1); foreach (var item in (validatingObject as IEnumerable))
{
ValidateObjectRecursively(errors, item, currentDepth + 1);
}
} }
}
//Do not recursively validate for enumerable objects
if (validatingObject is IEnumerable)
{
return; return;
} }
@ -102,7 +104,7 @@ namespace Volo.Abp.Validation
continue; continue;
} }
ValidateObjectRecursively(context, property.GetValue(validatingObject), currentDepth + 1); ValidateObjectRecursively(errors, property.GetValue(validatingObject), currentDepth + 1);
} }
} }
} }

Loading…
Cancel
Save