Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ICommandHandler/IQueryHandler with async/await

EDITH says (tl;dr)

I went with a variant of the suggested solution; keeping all ICommandHandlers and IQueryHandlers potentially aynchronous and returning a resolved task in synchronous cases. Still, I don't want to use Task.FromResult(...) all over the place so I defined an extension method for convenience:

public static class TaskExtensions
{
    public static Task<TResult> AsTaskResult<TResult>(this TResult result)
    {
        // Or TaskEx.FromResult if you're targeting .NET4.0 
        // with the Microsoft.BCL.Async package
        return Task.FromResult(result); 
    }
}

// Usage in code ...
using TaskExtensions;
class MySynchronousQueryHandler : IQueryHandler<MyQuery, bool>
{
    public Task<bool> Handle(MyQuery query)
    {
        return true.AsTaskResult();
    }
}

class MyAsynchronousQueryHandler : IQueryHandler<MyQuery, bool>
{
    public async Task<bool> Handle(MyQuery query)
    {
        return await this.callAWebserviceToReturnTheResult();
    }
}

It's a pity that C# isn't Haskell ... yet 8-). Really smells like an application of Arrows. Anyway, hope this helps anyone. Now to my original question :-)

Introduction

Hello there!

For a project I'm currently designing an application architecture in C# (.NET4.5, C#5.0, ASP.NET MVC4). With this question I hope to get some opinions about some issues I stumbled upon trying to incorporate async/await. Note: this is quite a lengthy one :-)

My solution structure looks like this:

  • MyCompany.Contract (Commands/Queries and common interfaces)
  • MyCompany.MyProject (Contains the business logic and command/query handlers)
  • MyCompany.MyProject.Web (The MVC web frontend)

I read up on maintainable architecture and Command-Query-Separation and found these posts very helpful:

  • Meanwhile on the query side of my architecture
  • Meanwhile on the command side of my architecture
  • Writing highly maintainable WCF services

So far I've got my head around the ICommandHandler/IQueryHandler concepts and dependency injection (I'm using SimpleInjector - it's really dead simple).

The Given Approach

The approach of the articles above suggests using POCOs as commands/queries and describes dispatchers of these as implementations of the following handler interfaces:

interface IQueryHandler<TQuery, TResult>
{
    TResult Handle(TQuery query);
}

interface ICommandHandler<TCommand>
{
    void Handle(TCommand command);
}

In a MVC Controller you'd use this as follows:

class AuthenticateCommand
{
    // The token to use for authentication
    public string Token { get; set; }
    public string SomeResultingSessionId { get; set; }
}

class AuthenticateController : Controller
{
    private readonly ICommandHandler<AuthenticateCommand> authenticateUser;

    public AuthenticateController(ICommandHandler<AuthenticateCommand> authenticateUser) 
    {
        // Injected via DI container
        this.authenticateUser = authenticateUser;
    }

    public ActionResult Index(string externalToken)
    {
        var command = new AuthenticateCommand 
        { 
            Token = externalToken 
        };
        this.authenticateUser.Handle(command);

        var sessionId = command.SomeResultingSessionId;
        // Do some fancy thing with our new found knowledge
    }
}

Some of my observations concerning this approach:

  1. In pure CQS only queries should return values while commands should be, well only commands. In reality it is more convenient for commands to return values instead of issuing the command and later doing a query for the thing the command should have returned in the first place (e.g. database ids or the like). That's why the author suggested putting a return value into the command POCO.
  2. It is not very obvious what is returned from a command, in fact it looks like the command is a fire and forget type of thing until you eventually encounter the weird result property being accessed after the handler has run plus the command now knows about it's result
  3. The handlers have to be synchronous for this to work - queries as well as commands. As it turns out with C#5.0 you can inject async/await powered handlers with the help of your favorite DI container, but the compiler doesn't know about that at compile time so the MVC handler will fail miserably with an exception telling you that the method returned before all asynchronous tasks finished executing.

Of course you can mark the MVC handler as async and this is what this question is about.

Commands Returning Values

I thought about the given approach and made changes to the interfaces to address issues 1. and 2. in that I added an ICommandHandler that has an explicit result type - just like the IQueryHandler. This still violates CQS but at least it is plain obvious that these commands return some sort of value with the additional benefit of not having to clutter the command object with a result property:

interface ICommandHandler<TCommand, TResult>
{
    TResult Handle(TCommand command);
}

Naturally one could argue that when you have the same interface for commands and queries why bother? But I think it's worth naming them differently - just looks cleaner to my eyes.

My Preliminary Solution

Then I thought hard of the 3rd issue at hand ... some of my command/query handlers need to be asynchronous (e.g. issuing a WebRequest to another web service for authentication) others don't. So I figured it would be best to design my handlers from the ground up for async/await - which of course bubbles up to the MVC handlers even for handlers that are in fact synchronous:

interface IQueryHandler<TQuery, TResult>
{
    Task<TResult> Handle(TQuery query);
}

interface ICommandHandler<TCommand>
{
    Task Handle(TCommand command);
}

interface ICommandHandler<TCommand, TResult>
{
    Task<TResult> Handle(TCommand command);
}

class AuthenticateCommand
{
    // The token to use for authentication
    public string Token { get; set; }

    // No more return properties ...
}

AuthenticateController:

class AuthenticateController : Controller
{
    private readonly ICommandHandler<AuthenticateCommand, string> authenticateUser;

    public AuthenticateController(ICommandHandler<AuthenticateCommand, 
        string> authenticateUser) 
    {
        // Injected via DI container
        this.authenticateUser = authenticateUser;
    }

    public async Task<ActionResult> Index(string externalToken)
    {
        var command = new AuthenticateCommand 
        { 
            Token = externalToken 
        };
        // It's pretty obvious that the command handler returns something
        var sessionId = await this.authenticateUser.Handle(command);

        // Do some fancy thing with our new found knowledge
    }
}

Although this solves my problems - obvious return values, all handlers can be async - it hurts my brain to put async on a thingy that isn't async just because. There are several drawbacks I see with this:

  • The handler interfaces are not as neat as I wanted them to be - the Task<...> thingys to my eyes are very verbose and at first sight obfuscate the fact that I only want to return something from a query/command
  • The compiler warns you about not having an appropriate await within synchronous handler implementations (I want to be able to compile my Release with Warnings as Errors) - you can overwrite this with a pragma ... yeah ... well ...
  • I could omit the async keyword in these cases to make the compiler happy but in order to implement the handler interface you would have to return some sort of Task explicitly - that's pretty ugly
  • I could supply synchronous and asynchronous versions of the handler interfaces (or put all of them in one interface bloating the implementation) but my understanding is that, ideally, 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. What if I need to make a formerly synchronous command async? I'd have to change every consumer of the handler potentially breaking semantics on my way through the code.
  • On the other hand the potentially-async-handlers-approach would even give me the ability to change sync handlers to be async by decorating them with the help of my DI container

Right now I don't see a best solution to this ... I'm at a loss.

Anyone having a similar problem and an elegant solution I didn't think of?

like image 901
mfeineis Avatar asked Jan 08 '14 00:01

mfeineis


2 Answers

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#.

like image 80
Stephen Cleary Avatar answered Oct 10 '22 03:10

Stephen Cleary


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

like image 41
Steven Avatar answered Oct 10 '22 04:10

Steven