Composite validator
See original GitHub issueHello, what do u think about this?
`private class Base {
public int Int1 { get; } = 1;
public string Str { get; } = string.Empty;
}
private class Nested : Base {
public int NestedInt1 { get; } = 2;
public string NestedStr { get; } = string.Empty;
}
private class Single {
public int SingleInt { get; } = 3;
public string SingleStr { get; } = string.Empty;
}
private class CompositeTestValidator : CompositeValidator {
public CompositeTestValidator() {
For<Base>(validator => {
validator.RuleFor(x => x.Int1).GreaterThan(2);
validator.RuleFor(x => x.Str).NotEmpty();
});
For<Nested>(validator => {
validator.RuleFor(x => x.NestedInt1).GreaterThan(3);
validator.RuleFor(x => x.NestedStr).NotEmpty();
});
For<Single>(validator => {
validator.RuleFor(x => x.SingleInt).GreaterThan(4);
validator.RuleFor(x => x.SingleStr).NotEmpty();
});
}
}
[Fact]
public void test_composite_validation() {
var composite = new CompositeTestValidator();
var validationResultNested = composite.Validate(new Nested());
var validationResultBase = composite.Validate(new Base());
var validationResultSingle = composite.Validate(new Single());
Assert.False(validationResultBase.IsValid);
Assert.False(validationResultNested.IsValid);
Assert.False(validationResultSingle.IsValid);
Assert.Equal(2, validationResultBase.Errors.Count);
Assert.Equal(4, validationResultNested.Errors.Count);
Assert.Equal(2, validationResultSingle.Errors.Count);
}`
And implementation:
`public abstract class CompositeValidator : ICompositeValidator {
private readonly IDictionary<Type, IValidator> _validators = new Dictionary<Type, IValidator>();
/// <inheritdoc>
/// <cref></cref>
/// </inheritdoc>
public ValidationResult Validate<T>(ValidationContext<T> context) {
var baseValidatorsStack = BuildBaseValidatorsStack<T>();
var validationResults = new List<ValidationResult>();
while (baseValidatorsStack.Any())
{
validationResults.Add(baseValidatorsStack.Pop().Validate(context));
}
if (_validators.ContainsKey(typeof(T)))
{
validationResults.Add(_validators[typeof(T)].Validate(context));
}
return new ValidationResult(validationResults.SelectMany(x => x.Errors));
}
/// <inheritdoc>
/// <cref></cref>
/// </inheritdoc>
public async Task<ValidationResult> ValidateAsync<T>(ValidationContext<T> context, CancellationToken cancellation = new CancellationToken()) {
var baseValidatorsStack = BuildBaseValidatorsStack<T>();
var validationResults = new List<ValidationResult>();
while (baseValidatorsStack.Any()) {
validationResults.Add(await baseValidatorsStack.Pop().ValidateAsync(context, cancellation));
}
if (_validators.ContainsKey(typeof(T))) {
validationResults.Add(await _validators[typeof(T)].ValidateAsync(context, cancellation));
}
return new ValidationResult(validationResults.SelectMany(x => x.Errors));
}
private Stack<IValidator> BuildBaseValidatorsStack<T>() {
var baseType = typeof(T).GetTypeInfo().BaseType;
var baseValidatorsStack = new Stack<IValidator>();
while (baseType != null)
{
if (_validators.ContainsKey(baseType) && baseType != typeof(T))
{
baseValidatorsStack.Push(_validators[baseType]);
}
baseType = baseType.GetTypeInfo().BaseType;
}
return baseValidatorsStack;
}
/// <inheritdoc>
/// <cref></cref>
/// </inheritdoc>
public ValidationResult Validate<T>(T instance) {
return Validate(BuildContext(instance));
}
/// <inheritdoc>
/// <cref></cref>
/// </inheritdoc>
public Task<ValidationResult> ValidateAsync<T>(T instance, CancellationToken cancellation = new CancellationToken()) {
return ValidateAsync(BuildContext(instance), cancellation);
}
private ValidationContext<T> BuildContext<T>(T instance) {
return new ValidationContext<T>(instance, new PropertyChain(), ValidatorOptions.ValidatorSelectors.DefaultValidatorSelectorFactory());
}
/// <inheritdoc>
/// <cref></cref>
/// </inheritdoc>
public void For<T>(Action<AbstractValidator<T>> configure)
{
var validator = new InlineValidator<T>();
_validators.Add(typeof(T), validator);
configure(validator);
}`
Anyway thank you for you time!
Issue Analytics
- State:
- Created 5 years ago
- Comments:6 (2 by maintainers)
Top Results From Across the Web
CompositeValidator (Oracle Role Manager API Reference)
A validator that can contain other validators. ... Gets the validators that constitute this composite validator. boolean, isRequired()
Read more >Composite Validation Rules | Laravel News
Validation Composite is a package by Paul Klimov that allows uniting several validation rules into a single one for easy reuse.
Read more >illuminatech/validation-composite: Allows uniting of several ...
Laravel Composite Validation. This extension allows uniting several Laravel validation rules into a single one for easy re-usage.
Read more >Composite validator · Issue #917 · FluentValidation ...
Personally I prefer not to use FluentValidation with inheritance hierarchies, and only use it with flattened data structures (eg view models), ...
Read more >How to pass the validator method to a composite component
The method and validation code works fine if I remove the composite component from my xhtml and just use a regular p:inputText. My...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I don’t think this is something we’d include in the core package - it’s not a common use case for FluentValidation, and it’s easy enough to implement yourself if you want this behaviour in your own project.
Hello. This seems like a reasonable approach. Personally I prefer not to use FluentValidation with inheritance hierarchies, and only use it with flattened data structures (eg view models), but if you want to use it this way you certainly can. I prefer your second approach (with
HierarchyValidator<T>
) over the CompositeValidator.Also just a tip, with github you need to use triple-backticks to create code blocks (see https://help.github.com/articles/creating-and-highlighting-code-blocks/)