mirror of https://github.com/abpframework/abp.git
15 changed files with 435 additions and 309 deletions
@ -0,0 +1,9 @@ |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.Validation |
|||
{ |
|||
public interface IMvcModelObjectValidator : IObjectValidator |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
using System.Collections.Generic; |
|||
using Microsoft.AspNetCore.Mvc.Abstractions; |
|||
using Microsoft.AspNetCore.Mvc.Filters; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.Validation |
|||
{ |
|||
public class MvcActionInvocationValidationContext : MethodInvocationValidationContext |
|||
{ |
|||
public ActionExecutingContext ActionContext { get; } |
|||
|
|||
public MvcActionInvocationValidationContext(ActionExecutingContext actionContext) |
|||
: base(actionContext.ActionDescriptor.GetMethodInfo(), GetParameterValues(actionContext)) |
|||
{ |
|||
ActionContext = actionContext; |
|||
} |
|||
|
|||
private static object[] GetParameterValues(ActionExecutingContext actionContext) |
|||
{ |
|||
var methodInfo = actionContext.ActionDescriptor.GetMethodInfo(); |
|||
|
|||
var parameters = methodInfo.GetParameters(); |
|||
var parameterValues = new object[parameters.Length]; |
|||
|
|||
for (var i = 0; i < parameters.Length; i++) |
|||
{ |
|||
parameterValues[i] = actionContext.ActionArguments.GetOrDefault(parameters[i].Name); |
|||
} |
|||
|
|||
return parameterValues; |
|||
} |
|||
} |
|||
} |
|||
@ -1,72 +1,37 @@ |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Microsoft.AspNetCore.Mvc.Abstractions; |
|||
using Microsoft.AspNetCore.Mvc.Filters; |
|||
using Microsoft.Extensions.Options; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.Validation |
|||
{ |
|||
public class MvcActionInvocationValidator : MethodInvocationValidator |
|||
public class MvcActionInvocationValidator : MethodInvocationValidatorBase |
|||
{ |
|||
protected ActionExecutingContext ActionContext { get; private set; } |
|||
|
|||
private bool _isValidatedBefore; |
|||
|
|||
public MvcActionInvocationValidator(IOptions<AbpValidationOptions> options) |
|||
: base(options) |
|||
// ReSharper disable once SuggestBaseTypeForParameter
|
|||
public MvcActionInvocationValidator(IMvcModelObjectValidator objectValidator) |
|||
: base(objectValidator) |
|||
{ |
|||
|
|||
} |
|||
|
|||
public void Initialize(ActionExecutingContext actionContext) |
|||
{ |
|||
ActionContext = actionContext; |
|||
|
|||
SetDataAnnotationAttributeErrors(); |
|||
|
|||
base.Initialize( |
|||
actionContext.ActionDescriptor.GetMethodInfo(), |
|||
GetParameterValues(actionContext) |
|||
); |
|||
} |
|||
|
|||
protected override void SetDataAnnotationAttributeErrors(object validatingObject) |
|||
public virtual void Validate(MvcActionInvocationValidationContext context) |
|||
{ |
|||
SetDataAnnotationAttributeErrors(); |
|||
AddModelStateErrors(context); |
|||
ValidateInternal(context); |
|||
} |
|||
|
|||
protected virtual void SetDataAnnotationAttributeErrors() |
|||
public virtual void AddModelStateErrors(MvcActionInvocationValidationContext context) |
|||
{ |
|||
if (_isValidatedBefore || ActionContext.ModelState.IsValid) |
|||
if (context.ActionContext.ModelState.IsValid) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
foreach (var state in ActionContext.ModelState) |
|||
foreach (var state in context.ActionContext.ModelState) |
|||
{ |
|||
foreach (var error in state.Value.Errors) |
|||
{ |
|||
ValidationErrors.Add(new ValidationResult(error.ErrorMessage, new[] { state.Key })); |
|||
context.Errors.Add(new ValidationResult(error.ErrorMessage, new[] { state.Key })); |
|||
} |
|||
} |
|||
|
|||
_isValidatedBefore = true; |
|||
} |
|||
|
|||
protected virtual object[] GetParameterValues(ActionExecutingContext actionContext) |
|||
{ |
|||
var methodInfo = actionContext.ActionDescriptor.GetMethodInfo(); |
|||
|
|||
var parameters = methodInfo.GetParameters(); |
|||
var parameterValues = new object[parameters.Length]; |
|||
|
|||
for (var i = 0; i < parameters.Length; i++) |
|||
{ |
|||
parameterValues[i] = actionContext.ActionArguments.GetOrDefault(parameters[i].Name); |
|||
} |
|||
|
|||
return parameterValues; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.Validation |
|||
{ |
|||
[ExposeServices(typeof(IMvcModelObjectValidator))] |
|||
public class MvcModelObjectValidator : ObjectValidator, IMvcModelObjectValidator |
|||
{ |
|||
public MvcModelObjectValidator(IOptions<AbpValidationOptions> options) |
|||
: base(options, NullDataAnnotationValidator.Instance) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.Validation |
|||
{ |
|||
public sealed class NullDataAnnotationValidator : IDataAnnotationValidator |
|||
{ |
|||
public static IDataAnnotationValidator Instance { get; } = new DataAnnotationValidator(); |
|||
|
|||
private NullDataAnnotationValidator() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public void AddDataAnnotationAttributeErrors(IAbpValidationResult validationResult, object validatingObject) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Linq; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Validation |
|||
{ |
|||
public class DataAnnotationValidator : IDataAnnotationValidator, ITransientDependency |
|||
{ |
|||
/// <summary>
|
|||
/// Checks all properties for DataAnnotations attributes.
|
|||
/// </summary>
|
|||
public virtual void AddDataAnnotationAttributeErrors(IAbpValidationResult validationResult, object validatingObject) |
|||
{ |
|||
var properties = TypeDescriptor.GetProperties(validatingObject).Cast<PropertyDescriptor>(); |
|||
foreach (var property in properties) |
|||
{ |
|||
var validationAttributes = property.Attributes.OfType<ValidationAttribute>().ToArray(); |
|||
if (validationAttributes.IsNullOrEmpty()) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
var validationContext = new ValidationContext(validatingObject) |
|||
{ |
|||
DisplayName = property.DisplayName, |
|||
MemberName = property.Name |
|||
}; |
|||
|
|||
foreach (var attribute in validationAttributes) |
|||
{ |
|||
var result = attribute.GetValidationResult(property.GetValue(validatingObject), validationContext); |
|||
if (result != null) |
|||
{ |
|||
validationResult.Errors.Add(result); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (validatingObject is IValidatableObject) |
|||
{ |
|||
var results = (validatingObject as IValidatableObject).Validate(new ValidationContext(validatingObject)); |
|||
validationResult.Errors.AddRange(results); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
|
|||
namespace Volo.Abp.Validation |
|||
{ |
|||
public interface IAbpValidationResult |
|||
{ |
|||
List<ValidationResult> Errors { get; } |
|||
|
|||
List<IShouldNormalize> ObjectsToBeNormalized { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Abp.Validation |
|||
{ |
|||
public interface IDataAnnotationValidator |
|||
{ |
|||
void AddDataAnnotationAttributeErrors(IAbpValidationResult validationResult, object validatingObject); |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
namespace Volo.Abp.Validation |
|||
{ |
|||
public interface IObjectValidator |
|||
{ |
|||
void Validate(IAbpValidationResult validationResult, object validatingObject); |
|||
|
|||
void AddValidatationErrors(IAbpValidationResult validationResult, object validatingObject); |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Reflection; |
|||
|
|||
namespace Volo.Abp.Validation |
|||
{ |
|||
public class MethodInvocationValidationContext : IAbpValidationResult |
|||
{ |
|||
public MethodInfo Method { get; } |
|||
|
|||
public object[] ParameterValues { get; } |
|||
|
|||
public ParameterInfo[] Parameters { get; } |
|||
|
|||
public List<ValidationResult> Errors { get; } |
|||
|
|||
public List<IShouldNormalize> ObjectsToBeNormalized { get; } |
|||
|
|||
public MethodInvocationValidationContext(MethodInfo method, object[] parameterValues) |
|||
{ |
|||
Method = method; |
|||
ParameterValues = parameterValues; |
|||
Parameters = method.GetParameters(); |
|||
|
|||
Errors = new List<ValidationResult>(); |
|||
ObjectsToBeNormalized = new List<IShouldNormalize>(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,250 +1,19 @@ |
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Reflection; |
|||
|
|||
namespace Volo.Abp.Validation |
|||
{ |
|||
/// <summary>
|
|||
/// This class is used to validate a method call (invocation) for method arguments.
|
|||
/// </summary>
|
|||
public class MethodInvocationValidator : ITransientDependency |
|||
public class MethodInvocationValidator : MethodInvocationValidatorBase |
|||
{ |
|||
private const int MaxRecursiveParameterValidationDepth = 8; |
|||
|
|||
protected MethodInfo Method { get; private set; } |
|||
protected object[] ParameterValues { get; private set; } |
|||
protected ParameterInfo[] Parameters { get; private set; } |
|||
protected List<ValidationResult> ValidationErrors { get; } |
|||
protected List<IShouldNormalize> ObjectsToBeNormalized { get; } |
|||
|
|||
private readonly AbpValidationOptions _options; |
|||
|
|||
/// <summary>
|
|||
/// Creates a new <see cref="MethodInvocationValidator"/> instance.
|
|||
/// </summary>
|
|||
public MethodInvocationValidator(IOptions<AbpValidationOptions> options) |
|||
{ |
|||
_options = options.Value; |
|||
|
|||
ValidationErrors = new List<ValidationResult>(); |
|||
ObjectsToBeNormalized = new List<IShouldNormalize>(); |
|||
} |
|||
|
|||
/// <param name="method">Method to be validated</param>
|
|||
/// <param name="parameterValues">List of arguments those are used to call the <paramref name="method"/>.</param>
|
|||
public virtual void Initialize(MethodInfo method, object[] parameterValues) |
|||
public MethodInvocationValidator(IObjectValidator objectValidator) |
|||
: base(objectValidator) |
|||
{ |
|||
Check.NotNull(method, nameof(method)); |
|||
Check.NotNull(parameterValues, nameof(parameterValues)); |
|||
|
|||
Method = method; |
|||
ParameterValues = parameterValues; |
|||
Parameters = method.GetParameters(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Validates the method invocation.
|
|||
/// </summary>
|
|||
public void Validate() |
|||
public virtual void Validate(MethodInvocationValidationContext context) |
|||
{ |
|||
CheckInitialized(); |
|||
|
|||
if (Parameters.IsNullOrEmpty()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (!Method.IsPublic) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (IsValidationDisabled()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (Parameters.Length != ParameterValues.Length) |
|||
{ |
|||
throw new Exception("Method parameter count does not match with argument count!"); |
|||
} |
|||
|
|||
if (ValidationErrors.Any() && HasSingleNullArgument()) |
|||
{ |
|||
ThrowValidationError(); |
|||
} |
|||
|
|||
for (var i = 0; i < Parameters.Length; i++) |
|||
{ |
|||
ValidateMethodParameter(Parameters[i], ParameterValues[i]); |
|||
} |
|||
|
|||
if (ValidationErrors.Any()) |
|||
{ |
|||
ThrowValidationError(); |
|||
} |
|||
|
|||
foreach (var objectToBeNormalized in ObjectsToBeNormalized) |
|||
{ |
|||
objectToBeNormalized.Normalize(); |
|||
} |
|||
} |
|||
|
|||
protected virtual void CheckInitialized() |
|||
{ |
|||
if (Method == null) |
|||
{ |
|||
throw new AbpException("This object has not been initialized. Call Initialize method first."); |
|||
} |
|||
} |
|||
|
|||
protected virtual bool IsValidationDisabled() |
|||
{ |
|||
if (Method.IsDefined(typeof(EnableValidationAttribute), true)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
return ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<DisableValidationAttribute>(Method) != null; |
|||
} |
|||
|
|||
protected virtual bool HasSingleNullArgument() |
|||
{ |
|||
return Parameters.Length == 1 && ParameterValues[0] == null; |
|||
} |
|||
|
|||
protected virtual void ThrowValidationError() |
|||
{ |
|||
throw new AbpValidationException( |
|||
"Method arguments are not valid! See ValidationErrors for details.", |
|||
ValidationErrors |
|||
); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Validates given parameter for given value.
|
|||
/// </summary>
|
|||
/// <param name="parameterInfo">Parameter of the method to validate</param>
|
|||
/// <param name="parameterValue">Value to validate</param>
|
|||
protected virtual void ValidateMethodParameter(ParameterInfo parameterInfo, object parameterValue) |
|||
{ |
|||
if (parameterValue == null) |
|||
{ |
|||
if (!parameterInfo.IsOptional && |
|||
!parameterInfo.IsOut && |
|||
!TypeHelper.IsPrimitiveExtendedIncludingNullable(parameterInfo.ParameterType, includeEnums: true)) |
|||
{ |
|||
ValidationErrors.Add(new ValidationResult(parameterInfo.Name + " is null!", new[] { parameterInfo.Name })); |
|||
} |
|||
|
|||
return; |
|||
} |
|||
|
|||
ValidateObjectRecursively(parameterValue, 1); |
|||
} |
|||
|
|||
protected virtual void ValidateObjectRecursively(object validatingObject, int currentDepth) |
|||
{ |
|||
if (currentDepth > MaxRecursiveParameterValidationDepth) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (validatingObject == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
SetDataAnnotationAttributeErrors(validatingObject); |
|||
|
|||
//Validate items of enumerable
|
|||
if (validatingObject is IEnumerable && !(validatingObject is IQueryable)) |
|||
{ |
|||
foreach (var item in (validatingObject as IEnumerable)) |
|||
{ |
|||
ValidateObjectRecursively(item, currentDepth + 1); |
|||
} |
|||
} |
|||
|
|||
//Add list to be normalized later
|
|||
if (validatingObject is IShouldNormalize) |
|||
{ |
|||
ObjectsToBeNormalized.Add(validatingObject as IShouldNormalize); |
|||
} |
|||
|
|||
//Do not recursively validate for enumerable objects
|
|||
if (validatingObject is IEnumerable) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var validatingObjectType = validatingObject.GetType(); |
|||
|
|||
//Do not recursively validate for primitive objects
|
|||
if (TypeHelper.IsPrimitiveExtendedIncludingNullable(validatingObjectType)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (_options.IgnoredTypes.Any(t => t.IsInstanceOfType(validatingObject))) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var properties = TypeDescriptor.GetProperties(validatingObject).Cast<PropertyDescriptor>(); |
|||
foreach (var property in properties) |
|||
{ |
|||
if (property.Attributes.OfType<DisableValidationAttribute>().Any()) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
ValidateObjectRecursively(property.GetValue(validatingObject), currentDepth + 1); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Checks all properties for DataAnnotations attributes.
|
|||
/// </summary>
|
|||
protected virtual void SetDataAnnotationAttributeErrors(object validatingObject) |
|||
{ |
|||
var properties = TypeDescriptor.GetProperties(validatingObject).Cast<PropertyDescriptor>(); |
|||
foreach (var property in properties) |
|||
{ |
|||
var validationAttributes = property.Attributes.OfType<ValidationAttribute>().ToArray(); |
|||
if (validationAttributes.IsNullOrEmpty()) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
var validationContext = new ValidationContext(validatingObject) |
|||
{ |
|||
DisplayName = property.DisplayName, |
|||
MemberName = property.Name |
|||
}; |
|||
|
|||
foreach (var attribute in validationAttributes) |
|||
{ |
|||
var result = attribute.GetValidationResult(property.GetValue(validatingObject), validationContext); |
|||
if (result != null) |
|||
{ |
|||
ValidationErrors.Add(result); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (validatingObject is IValidatableObject) |
|||
{ |
|||
var results = (validatingObject as IValidatableObject).Validate(new ValidationContext(validatingObject)); |
|||
ValidationErrors.AddRange(results); |
|||
} |
|||
ValidateInternal(context); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,113 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Reflection; |
|||
|
|||
namespace Volo.Abp.Validation |
|||
{ |
|||
public abstract class MethodInvocationValidatorBase : ITransientDependency |
|||
{ |
|||
private readonly IObjectValidator _objectValidator; |
|||
|
|||
protected MethodInvocationValidatorBase(IObjectValidator objectValidator) |
|||
{ |
|||
_objectValidator = objectValidator; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Validates the method invocation.
|
|||
/// </summary>
|
|||
protected virtual void ValidateInternal(MethodInvocationValidationContext context) |
|||
{ |
|||
Check.NotNull(context, nameof(context)); |
|||
|
|||
if (context.Parameters.IsNullOrEmpty()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (!context.Method.IsPublic) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (IsValidationDisabled(context)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (context.Parameters.Length != context.ParameterValues.Length) |
|||
{ |
|||
throw new Exception("Method parameter count does not match with argument count!"); |
|||
} |
|||
|
|||
if (context.Errors.Any() && HasSingleNullArgument(context)) |
|||
{ |
|||
ThrowValidationError(context); |
|||
} |
|||
|
|||
AddMethodParameterValidationErrors(context); |
|||
|
|||
if (context.Errors.Any()) |
|||
{ |
|||
ThrowValidationError(context); |
|||
} |
|||
|
|||
foreach (var objectToBeNormalized in context.ObjectsToBeNormalized) |
|||
{ |
|||
objectToBeNormalized.Normalize(); |
|||
} |
|||
} |
|||
|
|||
protected virtual bool IsValidationDisabled(MethodInvocationValidationContext context) |
|||
{ |
|||
if (context.Method.IsDefined(typeof(EnableValidationAttribute), true)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
return ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<DisableValidationAttribute>(context.Method) != null; |
|||
} |
|||
|
|||
protected virtual bool HasSingleNullArgument(MethodInvocationValidationContext context) |
|||
{ |
|||
return context.Parameters.Length == 1 && context.ParameterValues[0] == null; |
|||
} |
|||
|
|||
protected virtual void ThrowValidationError(MethodInvocationValidationContext context) |
|||
{ |
|||
throw new AbpValidationException( |
|||
"Method arguments are not valid! See ValidationErrors for details.", |
|||
context.Errors |
|||
); |
|||
} |
|||
|
|||
protected virtual void AddMethodParameterValidationErrors(MethodInvocationValidationContext context) |
|||
{ |
|||
for (var i = 0; i < context.Parameters.Length; i++) |
|||
{ |
|||
AddMethodParameterValidationErrors(context, context.Parameters[i], context.ParameterValues[i]); |
|||
} |
|||
} |
|||
|
|||
protected virtual void AddMethodParameterValidationErrors(IAbpValidationResult context, ParameterInfo parameterInfo, object parameterValue) |
|||
{ |
|||
if (parameterValue == null) |
|||
{ |
|||
if (!parameterInfo.IsOptional && |
|||
!parameterInfo.IsOut && |
|||
!TypeHelper.IsPrimitiveExtendedIncludingNullable(parameterInfo.ParameterType, includeEnums: true)) |
|||
{ |
|||
context.Errors.Add(new ValidationResult(parameterInfo.Name + " is null!", new[] { parameterInfo.Name })); |
|||
} |
|||
|
|||
return; |
|||
} |
|||
|
|||
_objectValidator.AddValidatationErrors(context, parameterValue); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,101 @@ |
|||
using System.Collections; |
|||
using System.ComponentModel; |
|||
using System.Linq; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Reflection; |
|||
|
|||
namespace Volo.Abp.Validation |
|||
{ |
|||
public class ObjectValidator : ITransientDependency, IObjectValidator |
|||
{ |
|||
private const int MaxRecursiveParameterValidationDepth = 8; |
|||
|
|||
private readonly AbpValidationOptions _options; |
|||
private readonly IDataAnnotationValidator _dataAnnotationValidator; |
|||
|
|||
public ObjectValidator(IOptions<AbpValidationOptions> options, IDataAnnotationValidator dataAnnotationValidator) |
|||
{ |
|||
_dataAnnotationValidator = dataAnnotationValidator; |
|||
_options = options.Value; |
|||
} |
|||
|
|||
public virtual void Validate(IAbpValidationResult validationResult, object validatingObject) |
|||
{ |
|||
AddValidatationErrors(validationResult, validatingObject); |
|||
|
|||
if (validationResult.Errors.Any()) |
|||
{ |
|||
throw new AbpValidationException( |
|||
"Method arguments are not valid! See ValidationErrors for details.", |
|||
validationResult.Errors |
|||
); |
|||
} |
|||
} |
|||
|
|||
public virtual void AddValidatationErrors(IAbpValidationResult validationResult, object validatingObject) |
|||
{ |
|||
ValidateObjectRecursively(validationResult, validatingObject, 1); |
|||
} |
|||
|
|||
protected virtual void ValidateObjectRecursively(IAbpValidationResult context, object validatingObject, int currentDepth) |
|||
{ |
|||
if (currentDepth > MaxRecursiveParameterValidationDepth) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (validatingObject == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
_dataAnnotationValidator.AddDataAnnotationAttributeErrors(context, validatingObject); |
|||
|
|||
//Validate items of enumerable
|
|||
if (validatingObject is IEnumerable && !(validatingObject is IQueryable)) |
|||
{ |
|||
foreach (var item in (validatingObject as IEnumerable)) |
|||
{ |
|||
ValidateObjectRecursively(context, item, currentDepth + 1); |
|||
} |
|||
} |
|||
|
|||
//Add list to be normalized later
|
|||
if (validatingObject is IShouldNormalize) |
|||
{ |
|||
context.ObjectsToBeNormalized.Add(validatingObject as IShouldNormalize); |
|||
} |
|||
|
|||
//Do not recursively validate for enumerable objects
|
|||
if (validatingObject is IEnumerable) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var validatingObjectType = validatingObject.GetType(); |
|||
|
|||
//Do not recursively validate for primitive objects
|
|||
if (TypeHelper.IsPrimitiveExtendedIncludingNullable(validatingObjectType)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (_options.IgnoredTypes.Any(t => t.IsInstanceOfType(validatingObject))) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var properties = TypeDescriptor.GetProperties(validatingObject).Cast<PropertyDescriptor>(); |
|||
foreach (var property in properties) |
|||
{ |
|||
if (property.Attributes.OfType<DisableValidationAttribute>().Any()) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
ValidateObjectRecursively(context, property.GetValue(validatingObject), currentDepth + 1); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue