Hooking into Mediator pipelines

Published: Monday 25 November 2019

We are going to be expanding on the mediator design pattern and seeing how we can hook into it's pipelines. However, if you are unfamiliar with what the mediator design pattern is, or just want a refresher, then I recommend reading my article entitled "How the Mediator Design Pattern Simplifies an Application". From that, we will be expanding the mediator example in that article.

To demonstrate hooking into mediator's pipelines, we are going to use MediatR. MediatR is descibed as a "Simple mediator implementation in .NET" on theirĀ GitHub repository

Pipelines

There are two pipelines we are going to demonstrate today. They are:

  • RequestPreProcessor
  • RequestPostProcessor

The RequestPreProcessor class runs just after we initialised the Request class. Whilst, the RequestPostProcessor class runs just after we have initialised the Response class.

Benefits

So what are the benefits of hooking into the pipeline? Well, one of them is that you can run the pipelines in completely separate assemblies. As long as those assemblies have access to the request and response classes, there is no reason why you can't run the pipeline in a separate assembly.

Example

For our example, we are going to expand on ourĀ previous mediator example. We are going to add a RequestPreProcessor and RequestPostProcessor class from the MediatR library. This is pretty simple to do as you can see below:

// AddRequest.cs
using MediatR;
 
namespace MediatR_Example.Models
{
	public class AddRequest : IRequest<AddResponse>
	{
		protected string sumAsText = null;

		public AddRequest(int numberOne, int numberTwo)
		{
			NumberOne = numberOne;
			NumberTwo = numberTwo;
		}

		public virtual int NumberOne { get; }

		public virtual int NumberTwo { get; }

		public virtual void WriteSumAsText()
		{
			sumAsText = NumberOne + " + " + NumberTwo;
		}

		public virtual void AddTotalToSum(int total)
		{
			sumAsText += " = " + total;
		}


	}
}
// AddRequestPostProcessor.cs
using MediatR.Pipeline;
using System.Threading;
using System.Threading.Tasks;
 
namespace MediatR_Example.Models
{
	public partial class AddRequestPostProcessor : IRequestPostProcessor<AddRequest, AddResponse>
	{
		public Task Process(AddRequest request, AddResponse response, CancellationToken cancellationToken)
		{
			request.AddTotalToSum(response.Total);
			return Task.CompletedTask;
		}
	}
}
// AddRequestPreProcessor.cs
using MediatR.Pipeline;
using System.Threading;
using System.Threading.Tasks;
 
namespace MediatR_Example.Models
{
	public partial class AddRequestPreProcessor : IRequestPreProcessor<AddRequest>
	{
		public Task Process(AddRequest request, CancellationToken cancellationToken)
		{
			request.WriteSumAsText();
			return Task.CompletedTask;
		}
	}
}

We have also added two new functions and a variable into the AddRequest class. The purpose of these is to call them when hooking into MediatR's pipeline.

RequestPreProcessor

So now the AddRequest class has ran and then it hooks into our RequestPreProcessor class. Called AddRequestPreProcessor, this class requires a reference to our initial AddRequest class. The AddRequestPreProcessor then calls the WriteSumAsText function inside AddRequest. The purpose of this function is to write the sum out into a string and store it in a string variable inside the AddRequest class.

RequestPostProcessor

The calculation has been ran and has returned the result to our AddResponse class. Now the RequestPostProcessor is ran. Called AddRequestPostProcessor, this class requires a reference to our initial AddRequest and AddResponse class. The AddRequestPostProcessor class then takes the result from the AddResponse class and calls the AddTotalToSum function from the AddRequest class.

This AddTotalToSum appends to the string that we created when we called the WriteSumAsText function and adds the answer to it.

C# coding challenges

C# coding challenges

Our online code editor allows you to compile the answer.

You can see a full demonstration of how this works in the video below: