CQRS and Domain Events

Domain Events are one of the gems of Domain Driven Design. One of the most asked questions about them when implemeting the CQRS pattern is when to fire them off.

I like the idea that Jimmy Bogard explains in his article A better domain events pattern, and that's to not dispatch them immediately but add them to a collection in the aggregate root for a later publication.

public interface IAggregateRoot  
{
  ICollection<IEvent> Events { get; }
}

We can add the domain events to the collection as shown in the following listing.

public Language(string name, string cultureName)  
{
  Id = Guid.NewGuid();
  Name = name;
  CultureName = cultureName;

  Events.Add(new LanguageCreatedEvent(Id, Name, CultureName));
}

His suggestion is then to dispatch those events in the data layer when the transaction is complete. If we are using Entity Framework we could do that into the SaveChanges method. I'm not a big fun of this approach because we should keep the data layer free of any business logic.

What about a command handler that returns a collection of domain events after our command has been executed and publish them in the command sender?

Let's assuming this is a standard way to define a command handler.

public interface ICommandHandler<in TCommand> where TCommand : ICommand  
{
  void Handle(TCommand command);
}

Change it in a way we can return a collection of domain events, like in the listing below.

public interface ICommandHandler<in TCommand> where TCommand : ICommand  
{
  ICollection<IEvent> Handle(TCommand command);
}

The following could be an implementation of our new interface.

public class CreateLanguageCommandHandler : ICommandHandler<CreateLanguageCommand>  
{
  private readonly IRepository _repository;
  private readonly IValidator<CreateLanguageCommand> _validator;

  public CreateLanguageCommandHandler(ILanguageRepository languageRepository,
  IValidator<CreateLanguageCommand> validator)
  {
    _languageRepository = languageRepository;
    _validator = validator;
  }

  public ICollection<IEvent> Handle(CreateLanguageCommand command)
  {
    var validationResult = _validator.Validate(command);

    if (!validationResult.IsValid)
    {
      throw new InvalidOperationException("Validation failed!");
    }

    var newLanguage = new Language(command.Name, command.CultureName);

    _languageRepository.Save(newLanguage);

    return newLanguage.Events;
  }
}

Below what the command sender could look like.

public class CommandSender : ICommandSender  
{
  private readonly IResolver _resolver;
  private readonly IEventPublisher _eventPublisher;

  public CommandSender(IResolver resolver, IEventPublisher eventPublisher)
  {
    _resolver = resolver;
    _eventPublisher = eventPublisher;
  }

  public void Send<TCommand>(TCommand command) where TCommand : ICommand
  {
    if (command == null)
    {
      throw new ArgumentNullException("command");
    }

    var commandHandler = _resolver.Resolve<ICommandHandler<TCommand>>();

    if (commandHandler == null)
    {
      throw new Exception(string.Format("No handler found for command '{0}'", command.GetType().FullName));
    }

    var events = commandHandler.Handle(command);

    foreach (var @event in events)
    {
      _eventPublisher.Publish(@event);
    }
  }
}

I think this is a clean solution without any particular cons, if any.

comments powered by Disqus