question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Composite validator

See original GitHub issue

Hello, 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:closed
  • Created 5 years ago
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
JeremySkinnercommented, Oct 11, 2018

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.

1reaction
JeremySkinnercommented, Oct 10, 2018

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/)

Read more comments on GitHub >

github_iconTop 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 >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found