Skip to content

Commands

xhafan edited this page Dec 17, 2018 · 27 revisions

CoreDdd encourages CQRS and application requests modifying an application state to be explicitly implemented as commands and command handlers. A command handler should be simple, and merely instantiate an aggregate root domain entity by either creating a new aggregate root entity or fetching an existing aggregate root entity from a database, and call a respective domain behaviour method on it. The complex domain code should live inside domain entities, and not inside command handlers.

A CoreDdd command implements ICommand interface, and a command handler implements ICommandHandler<TCommand> interface. CoreDdd provides a command handler base class BaseCommandHandler to derive your command handlers from, providing a helper method RaiseCommandExecutedEvent to raise a command executed event when you need to pass some data like generated Id to the caller of the command.

Create a new command, for instance create a new ship command:

public class CreateNewShipCommand : ICommand
{
    public string ShipName { get; set; }
    public decimal Tonnage { get; set; }
}

Add a new command handler:

public class CreateNewShipCommandHandler : BaseCommandHandler<CreateNewShipCommand>
{
    private readonly IRepository<Ship> _shipRepository;

    public CreateNewShipCommandHandler(IRepository<Ship> shipRepository)
    {
        _shipRepository = shipRepository;
    }

    public override async Task ExecuteAsync(CreateNewShipCommand command)
    {
        var newShip = new Ship(command.ShipName, command.Tonnage);
        await _shipRepository.SaveAsync(newShip);

        RaiseCommandExecutedEvent(new CommandExecutedArgs { Args = newShip.Id });
    }
}

Execute the command using the following code:

using (var unitOfWork = new NhibernateUnitOfWork(nhibernateConfigurator))
{
    unitOfWork.BeginTransaction();

    var shipRepository = new NhibernateRepository<Ship>(unitOfWork);
            
    try
    {
        var createNewShipCommand = new CreateNewShipCommand {ShipName = "lady", Tonnage = 10m };
        var createNewShipCommandHandler = new CreateNewShipCommandHandler(shipRepository);

        var generatedShipId = 0;
        createNewShipCommandHandler.CommandExecuted += args => generatedShipId = (int) args.Args;

        await createNewShipCommandHandler.ExecuteAsync(createNewShipCommand);

        Console.WriteLine($"Create new ship command was executed. Generated ship id: {generatedShipId}");

        await unitOfWork.CommitAsync();
    }
    catch
    {
        await unitOfWork.RollbackAsync();
        throw;
    }
}

The code sample above is available here as .NET Core console app.

Command executor

Another way how to execute a command is to use CoreDdd CommandExecutor. Instead of instantiating and executing the command handler directly, CommandExecutor can be used to instantiate and execute the command handler based on the command type:

var commandExecutor = new CommandExecutor(new FakeCommandHandlerFactory(unitOfWork));
var createNewShipCommand = new CreateNewShipCommand {ShipName = "lady", Tonnage = 10m };
await commandExecutor.ExecuteAsync(createNewShipCommand);

The code above uses FakeCommandHandlerFactory which is a command handler abstract factory implementation, which creates an instance of CreateNewShipCommandHandler based on the CreateNewShipCommand type.

The code sample above is available here.

Command executor with an IoC container

CommandExecutor is not supposed to be used directly, instead ICommandExecutor interface should be used together with an IoC container to execute commands. Most IoC containers (e.g. Castle Windsor or Ninject) are able to provide an abstract factory implementation out of the box, so no manual implementation like FakeCommandHandlerFactory is needed.

To start using CommandExecutor with an IoC container, add an IoC container into the project (e.g. Castle Windsor or Ninject) and register the components into the IoC container, Castle Windsor example:

ioCContainer.AddFacility<TypedFactoryFacility>();

ioCContainer.Register(
    Component.For<ICommandHandlerFactory>().AsFactory(), // register command handler factory (no real factory implementation needed :)
    Component.For<ICommandExecutor>() // register command executor
        .ImplementedBy<CommandExecutor>()
        .LifeStyle.Transient,
    Classes
        .FromAssemblyContaining<CreateNewShipCommand>() // register all command handlers in this assembly
        .BasedOn(typeof(ICommandHandler<>))
        .WithService.FirstInterface()
        .Configure(x => x.LifestyleTransient()),
    Component.For<INhibernateConfigurator>() // register nhibernate configurator
        .ImplementedBy<CoreDddSampleNhibernateConfigurator>()
        .LifeStyle.Singleton,
    Component.For<NhibernateUnitOfWork>() // register nhibernate unit of work
        .LifeStyle.PerThread,
    Component.For(typeof(IRepository<>)) // register repositories
        .ImplementedBy(typeof(NhibernateRepository<>))
        .LifeStyle.Transient

And then resolve ICommandExecutor and execute the command:

var commandExecutor = ioCContainer.Resolve<ICommandExecutor>();
var createNewShipCommand = new CreateNewShipCommand { ShipName = "lady", Tonnage = 10m };
await commandExecutor.ExecuteAsync(createNewShipCommand);

The code sample above is available here.

Command executor dependency injection

Now getting to a real life usage example. In the real life, an application component will get ICommandExecutor injected into a constructor by an IoC container:

public class ShipController
{
    private readonly ICommandExecutor _commandExecutor;

    public ShipController(ICommandExecutor commandExecutor)
    {
        _commandExecutor = commandExecutor;
    }

    public async Task<int> CreateNewShipAsync(string shipName, decimal tonnage)
    {
        var createNewShipCommand = new CreateNewShipCommand {ShipName = shipName, Tonnage = tonnage};

        var generatedShipId = 0;
        _commandExecutor.CommandExecuted += args => generatedShipId = (int)args.Args;

        await _commandExecutor.ExecuteAsync(createNewShipCommand);

        return generatedShipId;
    }
}

The code sample above is available here.

Domain behaviour on existing aggregate root domain entity

All code samples above execute CreateNewShipCommandHandler which creates a new aggregate root domain entity Ship. Let's see how to execute a domain behaviour on an existing persisted aggregate root domain entity. Add a new command update ship data command:

public class UpdateShipDataCommand : ICommand
{
    public int ShipId { get; set; }
    public string ShipName { get; set; }
    public decimal Tonnage { get; set; }
}

Add a command handler:

public class UpdateShipDataCommandHandler : BaseCommandHandler<UpdateShipDataCommand>
{
    private readonly IRepository<Ship> _shipRepository;

    public UpdateShipDataCommandHandler(IRepository<Ship> shipRepository)
    {
        _shipRepository = shipRepository;
    }

    public override async Task ExecuteAsync(UpdateShipDataCommand command)
    {
        var ship = await _shipRepository.GetAsync(command.ShipId);

        ship.UpdateData(command.ShipName, command.Tonnage);
    }
}

And here's a ShipController code to execute it:

public class ShipController
{
    private readonly ICommandExecutor _commandExecutor;

    public ShipController(ICommandExecutor commandExecutor)
    {
        _commandExecutor = commandExecutor;
    }

    public async Task UpdateShipData(int shipId, string shipName, decimal tonnage)
    {
        var updateShipDataCommand = new UpdateShipDataCommand
        {
            ShipId = shipId,
            ShipName = shipName,
            Tonnage = tonnage
        };
        await _commandExecutor.ExecuteAsync(updateShipDataCommand);
    }
}

The code sample above is available here.

You can’t perform that action at this time.