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)
{
var validationResult = new AbpValidationResult();
var errors = GetErrors(validatingObject);
AddErrors(validationResult, validatingObject);
if (validationResult.Errors.Any())
if (errors.Any())
{
throw new AbpValidationException(
"Object state is not valid! See ValidationErrors for details.",
validationResult.Errors
errors
);
}
}
/// <summary>
/// Checks all properties for DataAnnotations attributes.
/// Gets all errors from properties for DataAnnotations attributes and IValidatableObject interface.
/// </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>();
foreach (var property in properties)
{
var validationAttributes = property.Attributes.OfType<ValidationAttribute>().ToArray();
if (validationAttributes.IsNullOrEmpty())
{
continue;
}
AddPropertyErrors(validatingObject, property, errors);
}
var validationContext = new ValidationContext(validatingObject)
{
DisplayName = property.DisplayName,
MemberName = property.Name
};
if (validatingObject is IValidatableObject validatableObject)
{
errors.AddRange(
validatableObject.Validate(new ValidationContext(validatableObject))
);
}
foreach (var attribute in validationAttributes)
{
var result = attribute.GetValidationResult(property.GetValue(validatingObject), validationContext);
if (result != null)
{
validationResult.Errors.Add(result);
}
}
return errors;
}
protected virtual void AddPropertyErrors(object validatingObject, PropertyDescriptor property, List<ValidationResult> errors)
{
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));
validationResult.Errors.AddRange(results);
DisplayName = property.DisplayName,
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
{
public interface IDataAnnotationValidator
{
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
{
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!");
}
//todo: consider to remove this condition
if (context.Errors.Any() && HasSingleNullArgument(context))
{
ThrowValidationError(context);
@ -90,7 +91,7 @@ namespace Volo.Abp.Validation
parameterInfo.IsOut ||
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.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
@ -8,7 +9,7 @@ using Volo.Abp.Reflection;
namespace Volo.Abp.Validation
{
public class ObjectValidator : ITransientDependency, IObjectValidator
public class ObjectValidator : IObjectValidator, ITransientDependency
{
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)
{
var validationResult = new AbpValidationResult();
var errors = GetErrors(validatingObject, name, allowNull);
AddErrors(validationResult, validatingObject, name, allowNull);
if (validationResult.Errors.Any())
if (errors.Any())
{
throw new AbpValidationException(
"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)
{
validationResult.Errors.Add(
errors.Add(
name == null
? new ValidationResult("Given object is null!")
: 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)
{
@ -64,20 +67,19 @@ namespace Volo.Abp.Validation
return;
}
_dataAnnotationValidator.AddErrors(context, validatingObject);
errors.AddRange(_dataAnnotationValidator.GetErrors(validatingObject));
//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;
}
@ -102,7 +104,7 @@ namespace Volo.Abp.Validation
continue;
}
ValidateObjectRecursively(context, property.GetValue(validatingObject), currentDepth + 1);
ValidateObjectRecursively(errors, property.GetValue(validatingObject), currentDepth + 1);
}
}
}

Loading…
Cancel
Save