Manual Validation in A Mediatr RequestHandler without Exceptions

This is the second post in a 2 post series:

  1. Validation without Exceptions using a MediatR Pipeline Behavior; and
  2. Manual Validation in A Mediatr RequestHandler without Exceptions

In my last post, I covered a scenario of using a Mediatr Pipeline Behavior to perform validation of a command object in such a way that no exception is thrown in the event of a validation failure. Today, I’m going to cover another strategy which involves manual validation in the Business Layer, rather than handing it off to the framework (as described in that previous post).

There may be times where you need to perform manual validation in the business layer, for one reason or another. Perhaps some code needs to run before the validation is performed and this may not be something which can happen if the validation happens automatically in the Mediatr pipeline. In such a case, we are faced with the same challenge as in my previous post; how do we bubble a validation failure up to the View, without just doing the throw/catch exception thing?

The solution which I’m putting forward in this post uses a Functional Programming construct known as a Discriminated Union. But we’ll get to that in time. First I’ll set out the scenario. I’ll try to keep it simple, yet at the same time keep a realistic number of layers to be comparable to a real world application.

The trivial example which I will present will involve a simple validator which merely validates whether a collection of Colors is not empty. Again, using FluentValidation, such a validator would look like this:

public class ColourCollectionValidator : AbstractValidator<IEnumerable<ColourPayloadDto>>
{
	public ColourCollectionValidator()
	{
		RuleFor(c => c)
			.Must(c => c.Any())
			.WithMessage("The payload must contain at least one colour.");
	}
}

So, lets look at the service which will perform the validation. The relevant method in this service will need to return both the ValidationResult and the collection itself. For that, I will use the ValueTuple type, which is a handy data-structure which helps us keep down the number of DTOs in our project (we will have enough DTOs already, without having to create another little one for this little job).

public class ColoursService : IColoursService
{
	private readonly IValidator<IEnumerable<ColourPayloadDto>> _colourValidator;

	public ColoursService(IValidator<IEnumerable<ColourPayloadDto>> colourValidator)
	{
		_colourValidator = colourValidator;
	}

	public async Task<(ValidationResult ValidationResult, List<ColourPayloadDto> DTOs)> GetColoursAsync()
	{
		/************* NOTE: hard coding a list here. Would normally be populated by database or API call *************/
		var colourPayloadDtos = new List<ColourPayloadDto>
		{
			new ColourPayloadDto{ Id = Color.Gainsboro.ToArgb(), IsKnownColour = Color.Gainsboro.IsKnownColor, Colour = Color.Gainsboro.Name},
			new ColourPayloadDto{ Id = Color.SaddleBrown.ToArgb(), IsKnownColour = Color.SaddleBrown.IsKnownColor  ,Colour =Color.SaddleBrown.Name},
			new ColourPayloadDto{ Id = Color.PaleGreen.ToArgb(), IsKnownColour = Color.PaleGreen.IsKnownColor,Colour= Color.PaleGreen.Name},
			new ColourPayloadDto{ Id = Color.DarkBlue.ToArgb(), IsKnownColour = Color.DarkBlue.IsKnownColor,Colour= Color.DarkBlue.Name}
		};

		var validationResult = await _colourValidator.ValidateAsync(colourPayloadDtos);
		
		return (validationResult, colourPayloadDtos);
	}
}

So the calling code will have returned a ValueTuple with both the ValidationResult and the collection. The other great thing about this type is the named members i.e. ValidationResult and DTOs (hmmm intellisense). Before we get to calling that code, lets pop on over to the query side of our architecture with the query object that will be acted upon by our QueryHandler. The query object is:

public class GetColourQuery : IRequest<Either<List<ColourPayloadDto>, ValidationResult>>
{
	// Nothing to pass to the QueryHandler, so no properties.
}

And that brings us to the custom type Either, which I have obtained from Mikhail Shilkov’s blog (thanks Mikhail!) I’ll just dump the code of Either here and will discuss it further when we examine the code which consumes it:

public class Either<TL, TR>
{
	private readonly TL left;
	private readonly TR right;
	private readonly bool isLeft;

	public Either(TL left)
	{
		this.left = left;
		this.isLeft = true;
	}

	public Either(TR right)
	{
		this.right = right;
		this.isLeft = false;
	}

	public T Match<T>(Func<TL, T> leftFunc, Func<TR, T> rightFunc)
	{
		if (leftFunc == null)
		{
			throw new ArgumentNullException(nameof(leftFunc));
		}

		if (rightFunc == null)
		{
			throw new ArgumentNullException(nameof(rightFunc));
		}

		return this.isLeft ? leftFunc(this.left) : rightFunc(this.right);
	}

	/// <summary>
	/// If right value is assigned, execute an action on it.
	/// </summary>
	/// <param name="rightAction">Action to execute.</param>
	public void DoRight(Action<TR> rightAction)
	{
		if (rightAction == null)
		{
			throw new ArgumentNullException(nameof(rightAction));
		}

		if (!this.isLeft)
		{
			rightAction(this.right);
		}
	}

	public TL LeftOrDefault() => this.Match(l => l, r => default(TL));

	public TR RightOrDefault() => this.Match(l => default(TR), r => r);

	public static implicit operator Either<TL, TR>(TL left) => new Either<TL, TR>(left);

	public static implicit operator Either<TL, TR>(TR right) => new Either<TL, TR>(right);
}

The next piece of code which is relevant is the Query Handler. As per the GetColourQuery, the return type of the Handle method is Either<List<ColourPayloadDto>, ValidationResult> (wrapped in a Task). If you look at the body of that method, depending on whether the ValidationResult is valid, it returns 1 of 2 types of objects i.e. a List or a ValidationResult. So, you can see where the nomenclature for Either came from. How is this done? By the implicit operators of the Either class (otherwise known as the User-defined conversion operators). Because it is implicit, we don’t need to explicitly cast to either List or ValidationResult.

The implicit operators also toggle the all-important isLeft field, which determines what gets returned when the Match method is called (you’ll see where that comes in a bit further on).
public class GetColourQueryHandler : IRequestHandler<GetColourQuery, Either<List<ColourPayloadDto>, ValidationResult>>
{
	private readonly IColoursService _coloursService;

	public GetColourQueryHandler(IColoursService coloursService)
	{
		_coloursService = coloursService;
	}

	public async Task<Either<List<ColourPayloadDto>, ValidationResult>> Handle(GetColourQuery request, CancellationToken cancellationToken)
	{
		var result = await _coloursService.GetColoursAsync();
		
		if (!result.ValidationResult.IsValid)
			return result.ValidationResult;

		return result.DTOs;     
	}
}

This enables us to write code like this (note the invocation of Match):

[HttpGet]
[Route("[action]")]
public async Task<IActionResult> GetColours()
{
	var colours = await _mediator.Send(new GetColourQuery());

	return colours.Match(
		res => OkResponse(colours.LeftOrDefault()),
		res => BadRequest(colours.RightOrDefault())
		);
}

Where validation has passed, the OkResponse will be passed the list of DTOs. Otherwise, the BadRequest will be passed the ValidationResult (which will be a failed validation).

So, again we have achieved an elegant implementation which has enabled us to filter up to the View the validation failure without throwing an exception. Our code will be more performant and our runtime will be all the more happier for it!

Feel free to hit me up in the comments if you have another way of dealing with validation failures that does not involved throwing exceptions.

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Trackbacks and Pingbacks: