Command & Query: Domain - Mediator
Tags: csharp, dotnet, oop, cqs
Published: 2020-08-18 06:15:28

*The story is a part of the series about software architecture powered by command-query separation principle and aspect-oriented programming.*

***

## Example powered by requests and handlers

In the [preceding](https://dev.to/darjanbogdan/command-query-domain-abstract-model-662) chapter, the base model, which represents commands, queries, and their handlers, was explained and implemented as an abstract model in C#. Since the model consists of essentially two interfaces, it’s possible to provide a large variety of implementations making it suitable to model many business domains.

Simple user management will be taken as an example of one. Using the mentioned model as a backbone, many different actions on the *user* object will be implemented. To keep it clean and simple, only the user’s *unique identifier* and *name* are properties in focus. The class itself could be easily expanded or completely changed based on the business domain’s needs.

```csharp
public class User
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}
```

To implement the logic for getting a single User using its identifier, it’s necessary to implement two interfaces in separate classes. An instance of one class holds the data needed to perform a *task*, an instance of another holds the business logic to perform a *task*.

{% gist https://gist.github.com/darjanbogdan/e92d9c9ddb4b69212d268ba8cedc30f2 %}

`GetUserQuery` class implements `IRequest<User>` and carries the user identifier needed to get the user successfully. `GetUserQueryHandler` class, on the other hand, implements `IRequestHandler<GetUserQuery, User>` interface and has a method that performs the logic to get the user from some source. Simply, the method gets `GetUserQuery` object, passes `UserId` to the `GetUserFromSource` method to fetch the user and returns the retrieved `User` object. Data fetching and materialization are not in the focus at the moment, so `GetUserFromSource` could be virtually anything.

Following the example, the other actions on `User` object could be implemented similarly, using the same pair of generic interfaces or their derivatives such as `IRequest` and `IRequestHandler<TRequest>`.

Having all the handler implementations in place, with the help of a dependency injection container, each handler instance can be injected into another class. A typical Web API controller would look something like this:

{% gist https://gist.github.com/darjanbogdan/efd562a7e355171286caaee37bceb7d5 %}

What immediately comes to attention is the [constructor over-injection](https://blog.ploeh.dk/2018/08/27/on-constructor-over-injection/) smell, and as such should be avoided or reduced to a minimum, especially if it would appear regularly.

## Mediator — definition and model

Instead of individually injecting instances of [closed](https://docs.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/reflection-and-generic-types#is-the-type-or-method-open-or-closed) generic interfaces, a single non-generic interface with a generic method shall be used instead. Implementation of such interface serves as a [mediator](https://en.wikipedia.org/wiki/Mediator_pattern) between any *caller* and any request handler, effectively decoupling them from each other and completely removing the initial code-smell.

Although `IRequestHandlerMediator` seems like a reasonable choice to name such interface, I prefer to use `IBus` only because the base model can be furtherly expanded using various handler [decorators](https://en.wikipedia.org/wiki/Decorator_pattern) to form a pipeline and/or in-process bus.

The initial version of the interface and class implementation could look like this:

{% gist https://gist.github.com/darjanbogdan/77ad15ee4ac0e50546c6c90f437ab2c0 %}

As mentioned earlier, Bus implementation serves as a mediator, with the responsibility to invoke `Handle` method on a correct `handler` instance. Handler instantiation is usually managed by a dependency injection container, so `instanceFactory` function delegate is passed into the constructor as the only dependency of the implementation. It simply takes `Type` argument and returns an instance of that type as an `object`.

While looking simple and straightforward, to invoke `SendAsync` method both type parameters must be explicitly defined, which makes the usage inconvenient:

```csharp
var query = new GetUserQuery();
var user = await bus.SendAsync<GetUserQuery, User>(query, default);
```

[For a reason](https://stackoverflow.com/questions/9764357/does-c-sharp-support-type-inference-of-the-return-type/9765156#9765156) C#’s type inference doesn’t take return types into account, as a matter of fact, it fails immediately per specification:

> *If the supplied number of arguments is different than the number of parameters in the method, then inference immediately fails.* — [C# Language Specification](https://www.microsoft.com/en-us/download/details.aspx?id=7029), Version 5.0, § 7.5.2 Type Inference

Still, explicitly defined type parameters look noisy, especially when used frequently, with long descriptive type names. Considering that both `query` and `response` types are known at compile-time, writing simple clean code with type safety in place should be achievable:

```csharp
var query = new GetUserQuery();
var user = await bus.SendAsync(query, default);
```

To make the usage more pleasant, redundant data needs to be avoided meaning the `SendAsync` method signature needs to be adapted:

* `TRequest` type parameter removed — to match the number of method parameters and arguments

* Type of `request` argument changed to `IRequest<TResponse>` — to keep the same type constraint

With the constraints in place, implementation draft looks like the following:

{% gist https://gist.github.com/darjanbogdan/8d8fd9cab8797a90f5e48b3921f0e8b6 %}

Conforming to type inference rules leads to more complex implementation because the *concrete* type of request argument is unknown at the compile time. The absence of the type makes it impossible to construct the closed generic handler type which is required to get the correct handler instance via `instanceFactory` delegate.

There are different ways to solve the problem. For example, in *MediatR* library internal generic handler [wrappers](https://github.com/jbogard/MediatR/tree/master/src/MediatR/Internal) are used to solve the same issue.

In this case, only *Delegates* and *Reflection* are used to fill the gap. To have a reasonable solution, a few requirements and limitations must be met:

* Simple enough to be easily maintainable

* Performance in-line with existing solutions to be usable

* No `handler` instance caching to avoid [captive dependencies](https://blog.ploeh.dk/2014/06/02/captive-dependency/)

For simplicity, a naive implementation is shown, while a more comprehensive and optimized solution with safety checks and error handling in place can be found in *Pype* [repository](https://github.com/darjanbogdan/pype/blob/master/src/Pype/Bus.cs):

{% gist https://gist.github.com/darjanbogdan/dfd014953a72575a4e9f53e994e54349 %}

The simplest way to solve the problem is to reintroduce the initially implemented `SendAsync<TRequest, TResponse>` method with the small, but important difference. The type of `request` argument is `object`, not `TRequest` anymore.

The side-effect of casting back to `TRequest` is neglectable to the benefits of using [closed instance delegate](https://blog.slaks.net/2011/06/open-delegates-vs-closed-delegates.html) — to achieve fast and type-safe invocation via `SendAsyncDelegate<TResponse>` delegate. It wouldn’t be possible to use it if the argument’s type remained `TRequest`.

## Mediator — implementation benchmarking

There are many different ways to invoke `SendAsync<TRequest, TResponse>` function without knowing type parameters at compile time, some are:

* [MethodInfo.Invoke](https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.invoke?view=netcore-3.1) ([src](https://github.com/darjanbogdan/pype/blob/master/src/Pype.Benchmark/SendComparison/MethodInfoInvoke/BusMethodInfoInvoke.cs)) — type unsafe method invocation via reflection

* [Delegate.DynamicInvoke](https://docs.microsoft.com/en-us/dotnet/api/system.delegate.dynamicinvoke?view=netcore-3.1) ([src](https://github.com/darjanbogdan/pype/blob/master/src/Pype.Benchmark/SendComparison/DelegateDynamicInvoke/BusDelegateDynamicInvoke.cs)) — late-bound method invocation

* [dynamic](https://docs.microsoft.com/en-us/dotnet/api/system.dynamic?view=netcore-3.1) Invoke ([src](https://github.com/darjanbogdan/pype/blob/master/src/Pype.Benchmark/SendComparison/DynamicCastInvoke/BusDynamicCastInvoke.cs)) — non-statically typed method invocation

* [delegate](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/) Invoke ([src](https://github.com/darjanbogdan/pype/blob/master/src/Pype.Benchmark/SendComparison/DelegateInvoke/BusDelegateInvoke.cs)) — type-safe encapsulated method invocation

* [Func](https://docs.microsoft.com/en-us/dotnet/api/system.func-3?view=netcore-3.1) Invoke ([src](https://github.com/darjanbogdan/pype/blob/master/src/Pype.Benchmark/SendComparison/FuncInvoke/BusFuncInvoke.cs)) — invocation of Func<T1, T2, TResult> delegate type

* [Expression](https://docs.microsoft.com/en-us/dotnet/api/system.linq.expressions.expression.lambda?view=netcore-3.1) Invoke ([src](https://github.com/darjanbogdan/pype/blob/master/src/Pype.Benchmark/SendComparison/ExpressionFuncInvoke/BusExpressionFuncInvoke.cs)) — constructing and invoking lambda expression via expression trees

Using dedicated delegate type (as shown in the example) which represents the reference to the `SendAsync<TRequest, TResponse>` method is the most performant one. Based on a simple [benchmarking](https://github.com/darjanbogdan/pype/blob/master/src/Pype.Benchmark/SendComparison/SendComparisonBenchmarks.cs) using dummy `PingRequest` and `PingResponse`:

![Send method execution benchmarks chart](https://dev-to-uploads.s3.amazonaws.com/i/fdmmb9kjdf49xfh8z5y5.png)

Besides the mentioned approaches, *Generic invoke* presents the benchmarking of the initial version — the one with inconvenient API. It serves as a reference point to evaluate whether the trade-off between performance and convenience pays off.

Data sets (series) in the diagram are representing:

* ***Simple*** — a naive implementation for different method invocation approaches. As expected, each is slower by order of magnitude in comparison to the direct method invocation. In the case of expression trees, it’s even worse.

* ***Optimized*** — a reasonable implementation using caching where possible to avoid usually expensive interaction with System.Reflection namespace. The instantiation of methods, delegates, expressions or lamdas is completely mitigated by caching, invocation itself is almost the only thing that counts.

Although the best approach is still more than 2 times slower than the reference point, in absolute terms it’s only ~70ns slower which is negligible in most of the cases. Based on that and the [benchmarking](https://github.com/darjanbogdan/pype/tree/master/src/Pype.Benchmark/BusComparison) comparison with the other libraries, it’s safe to conclude that this kind of solution is efficient enough to be used on a daily basis.

To conclude, it’s always nice to see that extra effort to make a more convenient API paid off eventually:

1. Handler instances don’t have to be injected into their consumers, which makes their constructors *slim-fit*.

2. Handlers are completely decoupled from each other and the rest of the system which makes it more maintainable.

3. Handler invocation through `IBus` mediator comes with proper type inference support which makes the usage simple and code clean.

Finally, the fun part is reached, with the base model and mediator in place, it’s possible to expand the whole concept with many different cross-cutting aspects which will naturally fit into the whole picture. One of them, data validation, is covered in the [next](https://dev.to/darjanbogdan/command-query-domain-validation-2npo) chapter.

***

*All the gists, examples or solutions will be done in C# using the latest .Net Core/Standard versions and hosted on [Github](https://github.com/darjanbogdan?utf8=%E2%9C%93&tab=repositories&q=pype&type=public&language=c%23).*