Do queries and commands continue to be considered separate here?
Yes, typically you would fire a command and if you need to update the UI after this action has been performed you would perform a query to get the new information. An example will make this clear.
Let's say you would assign a specific guard to a certain area. The only information the command (which is only a DTO) needs is the Id
of the guard and the Id
of the area. The associated CommandHandler
will perform all tasks to handle this, e.g. removing that guard from another area, booking him as unavailable etc.
Now your UI would want to show the change. The UI has probably some kind of list with all guards and their assigned area. This list will be populated by a single GetActiveGuardsAndAreaQuery
which will return a List<GuardWithAreaInformationDto>
. This DTO
could contain all kinds of information about all guards. Returning this information from the command is not a clean separation of concerns, because the atomic command handling could be very well used from a similar but slightly different UI, which will require a slightly different update of the UI information.
such as a login attempt. Is that a query or a command?
IMO a login attempt is neither. It is a cross cutting concern, an implementation detail that the data is hidden behind a secure connection. The application however should not be concerned with this detail. Consider using the application with another customer where you could host the WebApi service in and Active Directory
domain where you can use Windows Authentication
. In that case the user only has to login to his machine and the security is handled by the client and server OS while communicating.
With the patterns you're referring to this can be nicely done using a AuthenticateToWebApiServiceCommandHandlerDecorator
which makes sure their are login credentials to serve to the service by asking the user in a modal form, reading it from a config file, or whatever.
Checking if the credentials worked can be done by performing a kind of a standard Query
your application always needs such as CheckIfUpdateIsAvailableQuery
. If the query succeeds the login attempt succeeded otherwise it failed.
if a command handler returns void, how would you tell the presenter whether or not the user creation request was successful?
While it seems that void
doesn't return anything this is not really true. Because if it doesn't fail with some exception (with a clear message what went wrong!) it must have succeeded.
In a follow up of the mentioned blog posts @dotnetjunkie describes a way to return information from commands but make notice of the added comment on the top of post.
To summarize, throw clear exceptions from failed commands. You can add an extra layer of abstraction client side to handle this nicely. Instead of injecting a commandhandler directly into the different presenters you can inject an IPromptableCommandHandler
which has only one open generic implementation at compile time:
public interface IPromptableCommandHandler<TCommand>
{
void Handle(TCommand command, Action succesAction);
}
public class PromptableCommandHandler<TCommand> : IPromptableCommandHandler<TCommand>
{
private readonly ICommandHandler<TCommand> commandHandler;
public PromptableCommandHandler(ICommandHandler<TCommand> commandHandler)
{
this.commandHandler = commandHandler;
}
public void Handle(TCommand command, Action succesAction)
{
try
{
this.commandHandler.Handle(command);
succesAction.Invoke();
}
catch (Exception)
{
MessageBox.Show("An error occured, please try again.");
// possible other actions like logging
}
}
}
// use as:
public void SetGuardActive(Guid guardId)
{
this.promptableCommandHandler.Handle(new SetGuardActiveCommand(guardId),() =>
this.RefreshGuardsList());
}
At the end of the day, for any given UI task (say the user creation request), does it end up that you end up having a winforms client based query/command, as well as a web api service version of the command/query which handles the request on that end?
No!
Client side you should create a single open generic CommandHandlerProxy
which solely task is to pass the command dto to the WebApi service.
For the service side architecture you should read another follow up: Writing Highly Maintainable WCF Services which describes an server side architecture to handle this very nicely. The linked project also contains an implementation for WebApi!