lucabriguglia / OpenCQRS

.NET Standard framework to create simple and clean design. Advanced features for DDD, CQRS and Event Sourcing.
Apache License 2.0
3 stars 115 forks source link

Composite commands #92

Closed quentin-villevieille closed 4 years ago

quentin-villevieille commented 4 years ago

Hi, I stumbled upon an interesting article yesterday about composite commands. Basically a composite command is a command container, each command being a container (or not). In the article, ICommand defines an Execute method to implement in deriving classes. But as far as I know, this can't be achieved with Kledex because of the way the commands work (correct me if I'm wrong). Maybe there's something I'm missing out somewhere ?

lucabriguglia commented 4 years ago

I like the idea behind it but not the suggested solution. If I understand it correctly, Execute() should be the equivalent of a Handle in a command handler (please correct me if I'm wrong). If I am right, how would you deal with dependency injection?

I think you can achieve something similar with Kledex using the event handlers. A command handler produces one or more events that can be automatically sent to the relative event handlers. You might create a sequence of commands and events to achieve the same result.

But a better solution may be a saga which is not currently supported in Kledex but it's something that I'd like to add.

lucabriguglia commented 4 years ago

The more I think about the idea and the more I like it. It should not be too complicated to implement something similar and reusing the current flow. I just need to find a clean way to pass a command response to the next command in the sequence.

lucabriguglia commented 4 years ago

I think we just need a new command handler interface with a handle method that accepts 2 parameters: command and command response of the previous command handler in the sequence.

lucabriguglia commented 4 years ago

I have implemented it quite easily. You can see the progress in this branch: https://github.com/lucabriguglia/Kledex/tree/issue-92-composite-commands

There is a sample console app to run: Kledex.Sample.CommandSequence.

lucabriguglia commented 4 years ago

This is how to use the new feature:

await dispatcher.SendAsync(
  new FirstCommand(), 
  new SecondCommand(), 
  new ThirdCommand());

Each command passes its response to the next one in the sequence.

And this is how to get a final result from the last command handler:

var result = await dispatcher.SendAsync<string>(
  new FirstCommand(), 
  new SecondCommand(), 
  new ThirdCommand());
quentin-villevieille commented 4 years ago

Nice ! I've just tried it, it works great. But I'm wondering if the controller has to know about the command sequence. I believe the sequence definition must be in the domain layer, and the controller would just call it from the domain.

lucabriguglia commented 4 years ago

Good point, should we create a separate class that holds the sequence?

quentin-villevieille commented 4 years ago

Yeah, I think so. We could name it SequenceCommand or somethinkg like that :)

lucabriguglia commented 4 years ago

Now we have:

public class SampleCommandSequence : CommandSequence
{
    public SampleCommandSequence()
    {
        AddCommand(new FirstCommand());
        AddCommand(new SecondCommand());
        AddCommand(new ThirdCommand());
     }
 }

And:

await dispatcher.SendAsync(new SampleCommandSequence());

Or:

var result = await dispatcher.SendAsync<string>(new SampleCommandSequence());
quentin-villevieille commented 4 years ago

That's spot on, thanks mate !

lucabriguglia commented 4 years ago

Released in version 2.3

lucabriguglia commented 4 years ago

Refer to #101 for new functionalities