ICommandHandler/IQueryHandler with async/await

You state:

the consumer of a handler shouldn't be aware of the fact that a command/query handler is sync or async as this is a cross cutting concern

Stephen Clearly already touched this a bit, but async is not a cross-cutting concern (or at least not the way it's implemented in .NET). Async is an architectural concern since you have to decide up front to use it or not, and it completely chances all your application code. It changes your interfaces and it's therefore impossible to 'sneak' this in, without the application to know about it.

Although .NET made async easier, as you said, it still hurts your eyes and mind. Perhaps it just needs mental training, but I'm really wondering whether it is all worth the trouble to go async for most applications.

Either way, prevent having two interfaces for command handlers. You must pick one, because having two separate interfaces will force you to duplicate all your decorators that you want to apply to them and duplicates your DI configation. So either have an interface that returns Task and uses output properties, or go with Task<TResut> and return some sort of Void type in case there is no return type.

As you can imagine (the articles you point at are mine) my personal preference is to have a void Handle or Task Handle method, since with commands, the focus is not on the return value and when having a return value, you will end up having a duplicate interface structure as the queries have:

public interface ICommand<TResult> { }

public interface ICommandHandler<TCommand, TResult> 
    where TCommand : ICommand<TResult> 
{ 
    Task<TResult> Handle(TCommand command);
}

Without the ICommand<TResult> interface and the generic type constraint, you will be missing compile time support. This is something I explained in Meanwhile... on the query side of my architecture


I created a project for just this - I wound up not splitting commands and queries, instead using request/response and pub/sub - https://github.com/jbogard/MediatR

public interface IMediator
{
    TResponse Send<TResponse>(IRequest<TResponse> request);
    Task<TResponse> SendAsync<TResponse>(IAsyncRequest<TResponse> request);
    void Publish<TNotification>(TNotification notification) where TNotification : INotification;
    Task PublishAsync<TNotification>(TNotification notification) where TNotification : IAsyncNotification;
}

For the case where commands don't return results, I used a base class that returned a Void type (Unit for functional folks). This allowed me to have a uniform interface for sending messages that have responses, with a null response being an explicit return value.

As someone exposing a command, you explicitly opt-in to being asynchronous in your definition of the request, rather than forcing everyone to be async.


Async and await don't mix perfectly with traditional OOP. I have a blog series on the subject; you may find the post on async interfaces helpful in particular (though I don't cover anything you haven't already discovered).

The design problems around async are extremely similar to the ones around IDisposable; it's a breaking change to add IDisposable to an interface, so you need to know whether any possible implementation may ever be disposable (an implementation detail). A parallel problem exists with async; you need to know whether any possible implementation may ever be asynchronous (an implementation detail).

For these reasons, I view Task-returning methods on an interface as "possibly asynchronous" methods, just like an interface inheriting from IDisposable means it "possibly owns resources."

The best approach I know of is:

  • Define any methods that are possibly-asynchronous with an asynchronous signature (returning Task/Task<T>).
  • Return Task.FromResult(...) for synchronous implementations. This is more proper than an async without an await.

This approach is almost exactly what you're already doing. A more ideal solution may exist for a purely functional language, but I don't see one for C#.