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 :-)
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:
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 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:
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.
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.
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:
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/commandawait
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 ...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 uglyRight 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?
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:
Task
/Task<T>
).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#.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With