EDITH says (tl;dr)
I went with a variant of the suggested solution; keeping all ICommandHandler
s and IQueryHandler
s 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:
- 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.
- 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
- 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 myRelease
withWarnings 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 ofTask
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?