This is Part 2 of a four-part series describing how to build an application in .NET using the Command-Query Responsibility Segregation (CQRS) and Event Sourcing (ES) patterns, as well as the SimpleCQRS NuGet package. Click here for Part 1.

UPDATE (Sep 6th 2016): Also check out my follow-up series, Real-World CQRS/ES with ASP.NET and Redis.

Now that we've got our Domain Objects defined, it's time start thinking about what kinds of functionality we want our application to handle. We can begin define this functionality by establishing what Commands the end users can send to our system.

What are Commands?

Commands are orders sent by the end user to the application, instructing the app to do something. When our application receives a command, a Command Handler will process it to figure out what the end-user wanted the app to do, and then kick off the appropriate Events to accomplish that task. All Commands will need to make some modification to the state of the data in our app (any command which unintentionally makes no change to the state of the data is an improper command, and any command which intentionally makes no change to the state of the data should be a query). In other words: commands are instructions from the end-user about what to modifications to make to the data stored in our app.

Defining the Commands

So we have domain objects for Movies and Movie Reviews. Let's list out the kinds of actions a user could take against those objects. A user could:

  • Add a movie
  • Edit an existing movie
  • Delete a movie
  • Add a review
  • Edit an existing review
  • Delete a review

Remember that "Get a Movie" or a "Get a Review" are not commands, they are queries and will be handled separately. For now, let's create a command for adding a movie to the database.

The command object itself will exist in the Contracts project in our solution, and the skeleton of the class looks like this:

public class CreateMovieCommand : ICommand
{
}

Notice that the command needs to implement ICommand which is defined by SimpleCQRS.

The properties of this command will be the data submitted to the application by the end user. In the case of a "create" command, the properties will be the same as the domain object being created. Our command now looks like this:

public class CreateMovieCommand : ICommand
{
    public string Title { get; set; }
    public DateTime ReleaseDate { get; set; }
    public int RunningTimeMinutes { get; set; }
    public CreateMovieCommand(string title, DateTime releaseDate, int runningTime)
    {
        Title = title;
        ReleaseDate = releaseDate;
        RunningTimeMinutes = runningTime;
    }
}

Notice that the command has no property for a collection of MovieReview objects. This is because we are treating the creation of a MovieReview as a distinct Command, which will be processed differently.

Creating a Command Handler

Now that we have the command we will be using, let's create a corresponding Command Handler class that will process the command. The Command Handlers go in the Application project in our solution. The skeleton for our command handler will look like this:

public enum CreateMovieStatus
{
    Successful
}
public class CreateMovieCommandHandler : CommandHandler<CreateMovieCommand>
{
    protected IDomainRepository _repository;

    public CreateMovieCommandHandler(IDomainRepository repository)
    {
        _repository = repository;
    }

    protected CreateMovieStatus ValidateCommand(CreateMovieCommand command)
    {
        return CreateMovieStatus.Successful;
    }
}

A Command Handler must inherit from CommandHandler<T>, where T is the type of the command being handled.

The IDomainRepository is an interface defined by SimpleCQRS that represents the repository for the event store itself. We won't actually need to implement that repository, we just need to set it up, and we'll do this in a later step.

Note also the enum CreateMovieStatus. SimpleCQRS includes functionality by which you can return enumerations for Create commands. Obviously, in a real-world application we'd have more values that just Successful but for now, we'll leave it as simple.

The next piece in setting up this command handler is to override a Handle method for the command being handled. We do this like so:

public override void Handle(CreateMovieCommand command)
{
    Return(ValidateCommand(command));

    var location = new Domain.Movie(Guid.NewGuid(), command.Title, command.ReleaseDate, command.RunningTimeMinutes);

    _repository.Save(location);
}

The real work comes in the Save() method call, which takes all the pending events in the created Domain Object and commits them to the event store.

Wait, you say what events? We didn't create any events! And you are correct; we didn't create any events yet. Let's do that.

What are Events?

Events are changes made to the state of the system that result from the end-user issuing Commands. They are serialized and stored in the Event Store, so that they can be recalled and re-executed at a later time (remember that this is a primary benefit of using Event Sourcing). Any number of Events may be raised from a single Command. In more concrete terms, events are classes.

Creating an Event

We already create a command for the creation of a Movie, so let's create an event for that command:

public class MovieCreatedEvent : DomainEvent
{
    public Guid MovieId
    {
        get { return AggregateRootId; }
        set { AggregateRootId = value;}
    }
}

Notice the inheritance from DomainEvent; this is so SimpleCQRS can use reflection to record the types of all the events we create.

The rest of the event is defined like so:

public class MovieCreatedEvent : DomainEvent
{
    public Guid MovieId
    {
        get { return AggregateRootId; }
        set { AggregateRootId = value;}
    }

    public string Title { get; set; }
    public DateTime ReleaseDate { get; set; }
    public int RunningTimeMinutes { get; set; }

    public MovieCreatedEvent(Guid movieId, string title, DateTime releaseDate, int runningTime)
    {
        MovieId = movieId;
        Title = title;
        ReleaseDate = releaseDate;
        RunningTimeMinutes = runningTime;
    }
}

Don't forget that this class represents the object that will be serialized and stored in the database, and as such it should have properties for every property of the domain object that can be changed as part of this event.

NOTE: Nothing prevents you from having separate events per Domain Object property, and in some scenarios that level of detail could be useful. There will be an example of this in Part 4 of this series.

Now that we have this event, we need to update the Domain Object we created back in Part 1:

public class Movie : AggregateRoot
{
    public string Title { get; set; }
    public DateTime ReleaseDate { get; set; }
    public int RunningTimeMinutes { get; set; }
    public List<MovieReview> Reviews { get; set; }

    public Movie(Guid movieId, string title, DateTime releaseDate, int runningTimeMinutes)
    {
        Apply(new MovieCreatedEvent(Guid.NewGuid(), title, releaseDate, runningTimeMinutes));
    }
}

The Apply() method stores an Event in the AggregateRoot's local event store, so that it can later be persisted to the Event Store proper. This makes sense: any time we create a Movie, we need to record an event stating that the Movie was created with these values. All this constructor now does is implement that idea.

There's one more step we need: implementing an Event Handler that deserializes the created Movie and adds it to the read store.

Creating an Event Handler

For the Event Handler, we need a class that implements IHandleDomainEvents<>:

public class MovieEventHandler : IHandleDomainEvents<MovieCreatedEvent>
{
    public void Handle(MovieCreatedEvent createdEvent)
    {
        throw new NotImplementedException();
    }
}

A single Event Handler can implement many IHandleDomainEvents. For now, let's create the implementation necessary for the existing Handle() method.

public class MovieEventHandler : IHandleDomainEvents<MovieCreatedEvent>
{
    public void Handle(MovieCreatedEvent createdEvent)
    {
        using (MoviesReadModel entities = new MoviesReadModel())
        {
            entities.Movies.Add(new Movie()
            {
                Id = createdEvent.AggregateRootId,
                Title = createdEvent.Title,
                ReleaseDate = createdEvent.ReleaseDate,
                RunningTimeMinutes = createdEvent.RunningTimeMinutes
            });

            entities.SaveChanges();
        }
    }
}

No tricks here: just regular Entity Framework creation.

There's one last piece we need, though: the Domain Object needs an event handler method, and the method must be named in accordance with the event. This method is what actually updates the state of the Domain Object any time an Event is executed against it. In our case, our Movie Domain Object needs the following method:

protected void OnMovieCreated(MovieCreatedEvent domainEvent)
{
    Id = domainEvent.AggregateRootId;
    Title = domainEvent.Title;
    ReleaseDate = domainEvent.ReleaseDate;
    RunningTimeMinutes = domainEvent.RunningTimeMinutes;
}

That method will be called automatically any time the corresponding event is processed by the event handler.

Summary

When creating commands and command handlers:

  1. The command object must implement ICommand.
  2. The command handler class must inherit from CommandHandler<>.
  3. The command handler must override a Handle() implementation for each command it handles.

When creating events and event handlers:

  1. The event object must inherit from DomainEvent.
  2. For creation events, the domain object must apply a creation event in its constructor.
  3. The event handler must implement IHandleDomainEvents, and can implement as many as necessary, with each one having a Handle() implementation.
  4. The domain object must have a corresponding method (e.g. MovieCreatedEvent -> OnMovieCreated).

Ta-da! Now we've created a CQRS/ES backend that we can start using! But how does an end-user call it? We'll discuss that in the next part of this series, which covers creating the end-user interface in ASP.NET Web API and the order of execution for this system.

If you'd like to see the code I built for this series, check out the GitHub repository.

Happy Coding!