Browse Source

Completely revised method validation.

pull/179/head
Halil İbrahim Kalkan 9 years ago
parent
commit
d52b2e776c
  1. 21
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/AbpValidationActionFilter.cs
  2. 9
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/IMvcModelObjectValidator.cs
  3. 33
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/MvcActionInvocationValidationContext.cs
  4. 59
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/MvcActionInvocationValidator.cs
  5. 15
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/MvcModelObjectValidator.cs
  6. 19
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/NullDataAnnotationValidator.cs
  7. 48
      src/Volo.Abp/Volo/Abp/Validation/DataAnnotationValidator.cs
  8. 12
      src/Volo.Abp/Volo/Abp/Validation/IAbpValidationResult.cs
  9. 7
      src/Volo.Abp/Volo/Abp/Validation/IDataAnnotationValidator.cs
  10. 9
      src/Volo.Abp/Volo/Abp/Validation/IObjectValidator.cs
  11. 29
      src/Volo.Abp/Volo/Abp/Validation/MethodInvocationValidationContext.cs
  12. 241
      src/Volo.Abp/Volo/Abp/Validation/MethodInvocationValidator.cs
  13. 113
      src/Volo.Abp/Volo/Abp/Validation/MethodInvocationValidatorBase.cs
  14. 101
      src/Volo.Abp/Volo/Abp/Validation/ObjectValidator.cs
  15. 28
      src/Volo.Abp/Volo/Abp/Validation/ValidationInterceptor.cs

21
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/AbpValidationActionFilter.cs

@ -1,8 +1,6 @@
using System; using System.Threading.Tasks;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Aspects; using Volo.Abp.Aspects;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
@ -10,17 +8,18 @@ namespace Volo.Abp.AspNetCore.Mvc.Validation
{ {
public class AbpValidationActionFilter : IAsyncActionFilter, ITransientDependency public class AbpValidationActionFilter : IAsyncActionFilter, ITransientDependency
{ {
private readonly IServiceProvider _serviceProvider; private readonly MvcActionInvocationValidator _validator;
public AbpValidationActionFilter(IServiceProvider serviceProvider) public AbpValidationActionFilter(MvcActionInvocationValidator validator)
{ {
_serviceProvider = serviceProvider; _validator = validator;
} }
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{ {
//TODO: Configuration to disable validation for controllers..? //TODO: Configuration to disable validation for controllers..?
if (!context.ActionDescriptor.IsControllerAction() ||
if (!context.ActionDescriptor.IsControllerAction() ||
!ActionResultHelper.IsObjectResult(context.ActionDescriptor.GetMethodInfo().ReturnType)) !ActionResultHelper.IsObjectResult(context.ActionDescriptor.GetMethodInfo().ReturnType))
{ {
await next(); await next();
@ -29,13 +28,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Validation
using (AbpCrossCuttingConcerns.Applying(context.Controller, AbpCrossCuttingConcerns.Validation)) using (AbpCrossCuttingConcerns.Applying(context.Controller, AbpCrossCuttingConcerns.Validation))
{ {
using (var scope = _serviceProvider.CreateScope()) _validator.Validate(new MvcActionInvocationValidationContext(context));
{
var validator = scope.ServiceProvider.GetRequiredService<MvcActionInvocationValidator>();
validator.Initialize(context);
validator.Validate();
}
await next(); await next();
} }
} }

9
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/IMvcModelObjectValidator.cs

@ -0,0 +1,9 @@
using Volo.Abp.Validation;
namespace Volo.Abp.AspNetCore.Mvc.Validation
{
public interface IMvcModelObjectValidator : IObjectValidator
{
}
}

33
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/MvcActionInvocationValidationContext.cs

@ -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;
}
}
}

59
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/MvcActionInvocationValidator.cs

@ -1,72 +1,37 @@
using System.Collections.Generic; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using Volo.Abp.Validation; using Volo.Abp.Validation;
namespace Volo.Abp.AspNetCore.Mvc.Validation namespace Volo.Abp.AspNetCore.Mvc.Validation
{ {
public class MvcActionInvocationValidator : MethodInvocationValidator public class MvcActionInvocationValidator : MethodInvocationValidatorBase
{ {
protected ActionExecutingContext ActionContext { get; private set; } // ReSharper disable once SuggestBaseTypeForParameter
public MvcActionInvocationValidator(IMvcModelObjectValidator objectValidator)
private bool _isValidatedBefore; : base(objectValidator)
public MvcActionInvocationValidator(IOptions<AbpValidationOptions> options)
: base(options)
{ {
} }
public void Initialize(ActionExecutingContext actionContext) public virtual void Validate(MvcActionInvocationValidationContext context)
{
ActionContext = actionContext;
SetDataAnnotationAttributeErrors();
base.Initialize(
actionContext.ActionDescriptor.GetMethodInfo(),
GetParameterValues(actionContext)
);
}
protected override void SetDataAnnotationAttributeErrors(object validatingObject)
{ {
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; return;
} }
foreach (var state in ActionContext.ModelState) foreach (var state in context.ActionContext.ModelState)
{ {
foreach (var error in state.Value.Errors) 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;
} }
} }
} }

15
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/MvcModelObjectValidator.cs

@ -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)
{
}
}
}

19
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/NullDataAnnotationValidator.cs

@ -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)
{
}
}
}

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

@ -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);
}
}
}
}

12
src/Volo.Abp/Volo/Abp/Validation/IAbpValidationResult.cs

@ -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; }
}
}

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

@ -0,0 +1,7 @@
namespace Volo.Abp.Validation
{
public interface IDataAnnotationValidator
{
void AddDataAnnotationAttributeErrors(IAbpValidationResult validationResult, object validatingObject);
}
}

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

@ -0,0 +1,9 @@
namespace Volo.Abp.Validation
{
public interface IObjectValidator
{
void Validate(IAbpValidationResult validationResult, object validatingObject);
void AddValidatationErrors(IAbpValidationResult validationResult, object validatingObject);
}
}

29
src/Volo.Abp/Volo/Abp/Validation/MethodInvocationValidationContext.cs

@ -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>();
}
}
}

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

@ -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 namespace Volo.Abp.Validation
{ {
/// <summary> /// <summary>
/// This class is used to validate a method call (invocation) for method arguments. /// This class is used to validate a method call (invocation) for method arguments.
/// </summary> /// </summary>
public class MethodInvocationValidator : ITransientDependency public class MethodInvocationValidator : MethodInvocationValidatorBase
{ {
private const int MaxRecursiveParameterValidationDepth = 8; public MethodInvocationValidator(IObjectValidator objectValidator)
: base(objectValidator)
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)
{ {
Check.NotNull(method, nameof(method));
Check.NotNull(parameterValues, nameof(parameterValues));
Method = method;
ParameterValues = parameterValues;
Parameters = method.GetParameters();
} }
/// <summary> public virtual void Validate(MethodInvocationValidationContext context)
/// Validates the method invocation.
/// </summary>
public void Validate()
{ {
CheckInitialized(); ValidateInternal(context);
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);
}
} }
} }
} }

113
src/Volo.Abp/Volo/Abp/Validation/MethodInvocationValidatorBase.cs

@ -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);
}
}
}

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

@ -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);
}
}
}
}

28
src/Volo.Abp/Volo/Abp/Validation/ValidationInterceptor.cs

@ -1,6 +1,4 @@
using System; using Volo.Abp.Aspects;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Aspects;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy; using Volo.Abp.DynamicProxy;
@ -8,11 +6,11 @@ namespace Volo.Abp.Validation
{ {
public class ValidationInterceptor : AbpInterceptor, ITransientDependency public class ValidationInterceptor : AbpInterceptor, ITransientDependency
{ {
private readonly IServiceProvider _serviceProvider; private readonly MethodInvocationValidator _validator;
public ValidationInterceptor(IServiceProvider serviceProvider) public ValidationInterceptor(MethodInvocationValidator validator)
{ {
_serviceProvider = serviceProvider; _validator = validator;
} }
public override void Intercept(IAbpMethodInvocation invocation) public override void Intercept(IAbpMethodInvocation invocation)
@ -23,14 +21,20 @@ namespace Volo.Abp.Validation
return; return;
} }
using (var scope = _serviceProvider.CreateScope()) Validate(invocation);
{
var validator = scope.ServiceProvider.GetRequiredService<MethodInvocationValidator>();
validator.Initialize(invocation.Method, invocation.Arguments);
validator.Validate();
}
invocation.Proceed(); invocation.Proceed();
} }
protected virtual void Validate(IAbpMethodInvocation invocation)
{
_validator
.Validate(
new MethodInvocationValidationContext(
invocation.Method,
invocation.Arguments
)
);
}
} }
} }

Loading…
Cancel
Save