'FluentValidation inside a MediatR pipeline and Razor Pages
I'm working on a project where everything is done through a mediatR pipeline.
To make things easy the pipeline is this : -> Validation -> Handler
The Validation layer is using FluentValidation and throws a ValidationException if something is wrong.
public class ValidationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : notnull
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidationBehaviour(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
if (_validators.Any())
{
var context = new ValidationContext<TRequest>(request);
var validationResults = await Task.WhenAll(_validators.Select(v => v.ValidateAsync(context, cancellationToken)));
var failures = validationResults.SelectMany(r => r.Errors).Where(f => f != null).ToList();
if (failures.Count != 0)
throw new ValidationException(failures);
}
return await next();
}
}
Everything is working fine up to now.
Now, I have my page handler like this :
[BindProperty]
public LoginCommand Data { get; set; }
public async Task<IActionResult> OnPostAsync(CancellationToken cancellationToken)
{
try
{
await _mediator.Send(Data, cancellationToken);
return LocalRedirect("/Index");
}
catch (ValidationException ex)
{
var res = new ValidationResult(ex.Errors);
res.AddToModelState(ModelState, nameof(Data));
return Page();
}
}
Doing things like this works fine, the drawback is that it makes a lot of code for every page handler.
Is there a way to simply this so the handler would look like this :
[BindProperty]
public LoginCommand Data { get; set; }
public async Task<IActionResult> OnPostAsync(CancellationToken cancellationToken)
{
await _mediator.Send(Data, cancellationToken);
return LocalRedirect("/Index");
}
and have this part of the code everywhere like a filter / middleware
try
{
// HANDLER CODE
}
catch (ValidationException ex)
{
var res = new ValidationResult(ex.Errors);
res.AddToModelState(ModelState, nameof(VIEWMODEL_NAME));
return Page();
}
Solution 1:[1]
You could add a ValidationExceptionPipelineBehavior
before the ValidationPipelineBehavior
in the MediatR pipeline.
That would ensure all ValidationException
s are caught.
Having an ExeptionPipelineBehavior
is fairly common.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | MatthiasA |