Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use command pattern in a WinForms client application?

Background

I'm building a two-tiered C# .net application:

  1. Tier 1: Winforms client application using the MVP (Model-View-Presenter) design pattern.
  2. Tier 2: WebAPI RESTful service sitting on top of Entity Framework and SQL Server.

If you would like more detail on the application I'm building, I gave a probably too thorough explanation here.

Current Development

Currently, I'm working on the Winforms client. Particularly, I'm trying to hash out a adequate implementation of the command pattern within this client. I was fortunate enough to stumble across this excellent blog post that outlines a solid command architecture. To complement that post, the author followed up by explaining how he separates queries from commands. After reading those blogs, it becomes very clear that my tier 2 (web api service) would greatly benefit from implementing both of these. The generic implementation allows for fantastic flexibility, testability, and extensibility.

Question

What is less clear to me is how I go about implementing these patterns on the winforms client side of things (tier 1). Do queries and commands continue to be considered separate here? Consider a basic action, such as a login attempt. Is that a query or a command? Ultimately, you need data back (user information on the server) from the web service, so that would make me think it is a query. What about another case, such as a request to create a new user. I understand that you would create a command object that stores the user information and send that off to the service. Commands are supposed to be fire and forget, but wouldn't you want some sort of confirmation from the service that the command was successful? Furthermore, if a command handler returns void, how would you tell the presenter whether or not the user creation request was successful?

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?

like image 927
Andrew Avatar asked Oct 19 '22 04:10

Andrew


1 Answers

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!

like image 65
Ric .Net Avatar answered Oct 21 '22 06:10

Ric .Net