5

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?

Community
  • 1
  • 1
Andrew
  • 893
  • 12
  • 28

1 Answers1

3

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!

Steven
  • 166,672
  • 24
  • 332
  • 435
Ric .Net
  • 5,540
  • 1
  • 20
  • 39
  • Thank you again @Ric , I appreciate your time! To ensure I'm understanding what has been said, let me rehash: For a command, the winforms client will create a command object (a DTO). This command object will get passed to the command handler as a parameter in the handle method. However, the command handler in the winforms client is just a generic proxy that passes the command to the web api where the actual command resides (i.e. the proxy could be injected into the PromptableComandHandler). Does that sound correct? Are queries also handled via proxies in the same way? – Andrew Aug 01 '16 at 07:00
  • 1
    @Andrew Yes you understood correctly. Queries follow the same pattern. Notice that the mentioned proxy implements ICommandHandler, but is a open generic implementation which handles all commands the same way – Ric .Net Aug 01 '16 at 09:16
  • Awesome, thanks @Ric for the confirmation, I did notice that! That's pretty powerful stuff. Another quick question: are commands and queries (the DTOs) generally supposed to be flat (just properties), or can they be comprised of other objects? – Andrew Aug 02 '16 at 18:34
  • 1
    They can be composed of other DTO's as long as the deepest level only has properties and no behavior. They should be completely free of behavior, that's the core of this design. – Ric .Net Aug 02 '16 at 20:08
  • Thank you @Ric! From what I can tell, in the SolidServices code example for the Maintinable WCF Services blog, it looks like the client application is only using the WCF service, not the Web Api. Looking at the routes defined in the Api, I see `api/commands/{command}`, `api/queries/{query}`, and `api/{controller}/{action}/{id}`. What is an appropriate method for creating the URI for a command when setting up an `HttpClient` request on the client side of things, given that all commands come from a generic command proxy? Do you just build a string `"api/commands/" + commandObject.ToString;`? – Andrew Aug 03 '16 at 14:25
  • And, what would `api/{controller}/{action}/{id}` be used for? What kind of action does not fit into a command or query? – Andrew Aug 03 '16 at 14:28
  • Did you see the repository moved to GitHub? The WebApi can be found here https://github.com/dotnetjunkie/solidservices/tree/master/src/WebApiService – Ric .Net Aug 03 '16 at 18:29
  • 1
    @Andrew: The `WebApiCommandHandlerProxy` implementation (that is missing from the SOLIDServices project) should typically construct the URL as follows: `"api/commands/" + typeof(TCommand).Name`. The `api/{controller}/{action}/{id}` is there just because I never removed it. You typically wont need it, since everything is either a command or a query. – Steven Aug 03 '16 at 18:31
  • Looks like I was on the right track @Steven! Ric, I did find the implementation of the Web API. I was just mentioning that the client application in that solution made calls to the WCF service, and none to the Web API, so I was looking for the correct method to create the Web API httpclient requests. Steven has pointed me in the right direction. Thank you both! – Andrew Aug 03 '16 at 20:02
  • @Andrew: I should clearly update the SOLIDServices project to add WebApi client code as well. – Steven Aug 03 '16 at 20:03
  • 1
    @Steven: While that would help, it would never be expected! Your blogs have already helped me so much. :) – Andrew Aug 03 '16 at 20:06