mirror of https://github.com/abpframework/abp.git
15 changed files with 253 additions and 244 deletions
@ -1,55 +0,0 @@ |
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Linq; |
|||
using FluentValidation; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace Volo.Abp.FluentValidation |
|||
{ |
|||
public class FluentMethodInvocationValidator : IMethodInvocationValidator, ITransientDependency |
|||
{ |
|||
private readonly IServiceProvider _serviceProvider; |
|||
|
|||
public FluentMethodInvocationValidator( |
|||
IServiceProvider serviceProvider) |
|||
{ |
|||
_serviceProvider = serviceProvider; |
|||
} |
|||
|
|||
public void Validate(MethodInvocationValidationContext context) |
|||
{ |
|||
var validationResult = new AbpValidationResult(); |
|||
|
|||
foreach (var parameterValue in context.ParameterValues) |
|||
{ |
|||
var serviceType = typeof(IValidator<>).MakeGenericType(parameterValue.GetType()); |
|||
var validator = _serviceProvider.GetService(serviceType) as IValidator; |
|||
if (validator == null) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
var result = validator.Validate(parameterValue); |
|||
if (!result.IsValid) |
|||
{ |
|||
validationResult.Errors.AddRange( |
|||
result.Errors.Select( |
|||
error => |
|||
new ValidationResult(error.ErrorMessage) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
if (validationResult.Errors.Any()) |
|||
{ |
|||
//TODO: How to localize messages?
|
|||
throw new AbpValidationException( |
|||
"Method arguments are not valid! See ValidationErrors for details.", |
|||
context.Errors |
|||
); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
using FluentValidation; |
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Linq; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace Volo.Abp.FluentValidation |
|||
{ |
|||
public class FluentObjectValidationContributor : IObjectValidationContributor, ITransientDependency |
|||
{ |
|||
private readonly IServiceProvider _serviceProvider; |
|||
|
|||
public FluentObjectValidationContributor( |
|||
IServiceProvider serviceProvider) |
|||
{ |
|||
_serviceProvider = serviceProvider; |
|||
} |
|||
|
|||
public void AddErrors(ObjectValidationContext context) |
|||
{ |
|||
var serviceType = typeof(IValidator<>).MakeGenericType(context.ValidatingObject.GetType()); |
|||
var validator = _serviceProvider.GetService(serviceType) as IValidator; |
|||
if (validator == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var result = validator.Validate(context.ValidatingObject); |
|||
if (!result.IsValid) |
|||
{ |
|||
context.Errors.AddRange( |
|||
result.Errors.Select( |
|||
error => |
|||
new ValidationResult(error.ErrorMessage) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,122 @@ |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Linq; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Reflection; |
|||
|
|||
namespace Volo.Abp.Validation |
|||
{ |
|||
public class DataAnnotationObjectValidationContributor : IObjectValidationContributor, ITransientDependency |
|||
{ |
|||
public const int MaxRecursiveParameterValidationDepth = 8; |
|||
|
|||
protected AbpValidationOptions Options { get; } |
|||
|
|||
public DataAnnotationObjectValidationContributor(IOptions<AbpValidationOptions> options) |
|||
{ |
|||
Options = options.Value; |
|||
} |
|||
|
|||
public void AddErrors(ObjectValidationContext context) |
|||
{ |
|||
ValidateObjectRecursively(context.Errors, context.ValidatingObject, currentDepth: 1); |
|||
} |
|||
|
|||
protected virtual void ValidateObjectRecursively(List<ValidationResult> errors, object validatingObject, int currentDepth) |
|||
{ |
|||
if (currentDepth > MaxRecursiveParameterValidationDepth) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (validatingObject == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
AddErrors(errors, validatingObject); |
|||
|
|||
//Validate items of enumerable
|
|||
if (validatingObject is IEnumerable) |
|||
{ |
|||
if (!(validatingObject is IQueryable)) |
|||
{ |
|||
foreach (var item in (validatingObject as IEnumerable)) |
|||
{ |
|||
ValidateObjectRecursively(errors, item, currentDepth + 1); |
|||
} |
|||
} |
|||
|
|||
return; |
|||
} |
|||
|
|||
var validatingObjectType = validatingObject.GetType(); |
|||
|
|||
//Do not recursively validate for primitive objects
|
|||
if (TypeHelper.IsPrimitiveExtended(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(errors, property.GetValue(validatingObject), currentDepth + 1); |
|||
} |
|||
} |
|||
|
|||
public void AddErrors(List<ValidationResult> errors, object validatingObject) |
|||
{ |
|||
var properties = TypeDescriptor.GetProperties(validatingObject).Cast<PropertyDescriptor>(); |
|||
|
|||
foreach (var property in properties) |
|||
{ |
|||
AddPropertyErrors(validatingObject, property, errors); |
|||
} |
|||
|
|||
if (validatingObject is IValidatableObject validatableObject) |
|||
{ |
|||
errors.AddRange( |
|||
validatableObject.Validate(new ValidationContext(validatableObject)) |
|||
); |
|||
} |
|||
} |
|||
|
|||
protected virtual void AddPropertyErrors(object validatingObject, PropertyDescriptor property, List<ValidationResult> errors) |
|||
{ |
|||
var validationAttributes = property.Attributes.OfType<ValidationAttribute>().ToArray(); |
|||
if (validationAttributes.IsNullOrEmpty()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
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) |
|||
{ |
|||
errors.Add(result); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,71 +0,0 @@ |
|||
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 |
|||
{ |
|||
public void Validate(object validatingObject) |
|||
{ |
|||
var errors = GetErrors(validatingObject); |
|||
|
|||
if (errors.Any()) |
|||
{ |
|||
throw new AbpValidationException( |
|||
"Object state is not valid! See ValidationErrors for details.", |
|||
errors |
|||
); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets all errors from properties for DataAnnotations attributes and IValidatableObject interface.
|
|||
/// </summary>
|
|||
public virtual List<ValidationResult> GetErrors(object validatingObject) |
|||
{ |
|||
var errors = new List<ValidationResult>(); |
|||
var properties = TypeDescriptor.GetProperties(validatingObject).Cast<PropertyDescriptor>(); |
|||
|
|||
foreach (var property in properties) |
|||
{ |
|||
AddPropertyErrors(validatingObject, property, errors); |
|||
} |
|||
|
|||
if (validatingObject is IValidatableObject validatableObject) |
|||
{ |
|||
errors.AddRange( |
|||
validatableObject.Validate(new ValidationContext(validatableObject)) |
|||
); |
|||
} |
|||
|
|||
return errors; |
|||
} |
|||
|
|||
protected virtual void AddPropertyErrors(object validatingObject, PropertyDescriptor property, List<ValidationResult> errors) |
|||
{ |
|||
var validationAttributes = property.Attributes.OfType<ValidationAttribute>().ToArray(); |
|||
if (validationAttributes.IsNullOrEmpty()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
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) |
|||
{ |
|||
errors.Add(result); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,12 +0,0 @@ |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
|
|||
namespace Volo.Abp.Validation |
|||
{ |
|||
public interface IDataAnnotationValidator |
|||
{ |
|||
void Validate(object validatingObject); |
|||
|
|||
List<ValidationResult> GetErrors(object validatingObject); |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Abp.Validation |
|||
{ |
|||
public interface IObjectValidationContributor |
|||
{ |
|||
void AddErrors(ObjectValidationContext context); |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.Validation |
|||
{ |
|||
public class ObjectValidationContext |
|||
{ |
|||
[NotNull] |
|||
public object ValidatingObject { get; } |
|||
|
|||
public List<ValidationResult> Errors { get; } |
|||
|
|||
public ObjectValidationContext([NotNull] object validatingObject) |
|||
{ |
|||
ValidatingObject = Check.NotNull(validatingObject, nameof(validatingObject)); |
|||
Errors = new List<ValidationResult>(); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue