cqrs-validation-mediatr-fluentvalidation icon indicating copy to clipboard operation
cqrs-validation-mediatr-fluentvalidation copied to clipboard

How to use MustAsync in Pipeline

Open P9avel opened this issue 3 years ago • 2 comments

Hello, thank for you example. I am want to use Validator like

public class CustomerValidator : AbstractValidator<Customer> { SomeExternalWebApiClient _client;

public CustomerValidator(SomeExternalWebApiClient client) { _client = client;

RuleFor(x => x.Id).MustAsync(async (id, cancellation) => 
{
  bool exists = await _client.IdExists(id);
  return !exists;
}).WithMessage("ID Must be unique");

} }

When i am used this code, i am recive exception in line

public sealed class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : class, ICommand<TResponse> { private readonly IEnumerable<IValidator<TRequest>> _validators; public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators) => _validators = validators; public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next) { if (!_validators.Any()) { return await next(); } var context = new ValidationContext<TRequest>(request); var errorsDictionary = _validators .Select(x => x.Validate(context)) <-- Exceptions here, need to call ValidateAsync .SelectMany(x => x.Errors) .Where(x => x != null) .GroupBy( x => x.PropertyName, x => x.ErrorMessage, (propertyName, errorMessages) => new { Key = propertyName, Values = errorMessages.Distinct().ToArray() }) .ToDictionary(x => x.Key, x => x.Values);

Can you to modify code for old cases (sync validators) and for new case (MustAsync calls)?

P9avel avatar Jul 19 '22 17:07 P9avel

Hi, maybe you have to do something like this :

 var context = new ValidationContext<TRequest>(request);

            var tasks = _validators.Select(x => x.ValidateAsync(context, cancellationToken));
            var result = await Task.WhenAll(tasks);

            var add = result.SelectMany(x => x.Errors)
                .Where(x => x != null)
                .GroupBy(
                    x => x.PropertyName,
                    x => x.ErrorMessage,
                    (propertyName, errorMessages) => new
                    {
                        Key = propertyName,
                        Values = errorMessages.Distinct().ToArray()
                    })
                .ToDictionary(x => x.Key, x => x.Values);

then you have to combine Validate Dictionary + ValidateAsync. But I don't like this approach, I prefer to check it in Handler. The validator shouldn't be heavy.

RybalkoValeriy avatar Aug 20 '22 20:08 RybalkoValeriy

many thx for your code

P9avel avatar Aug 21 '22 09:08 P9avel