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

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

Now that we've discussed why we want to implement CQRS and ES, let's start the conversation of exactly how to do so. In this series, we will build a fully-functional CQRS/ES and Web API application using a NuGet packages called SimpleCQRS; discuss the individual components of a CQRS/ES application, and discuss some benefits and drawbacks to using this particular solution.

Components of a CQRS/ES Application

Remember that Command-Query Responsibility Segregation states that we have separate Read and Write models, and Event Sourcing states that we have an append-only data store that contains the changes made to our data, stored as serialized events. The full architecture looks like this:


Source: CQRS Journey on MSDN

In order to implement that architecture, we need to build several related pieces. Here's what we need:

  • Domain Objects: Classes that represent how our data is modeled on the read side.
  • Commands: Classes that represent commands made by the end user, that will be processed by the application.
  • Command Handlers: Classes that will interpret commands and kick off corresponding Events.
  • Events: Classes that represent changes made to the data in the data store, and are kicked off by Commands. These classes are serialized into the Event Store. One Command may kick off many Events.
  • Event Handlers: Classes that interpret the Events and store them into the Event Store.
  • Command Bus: A class that represents the queue for the Commands. Commands placed on the bus are processed by one or more appropriate Command Handlers.
  • Event Bus: A class that represents the queue for the Events. Events placed on this bus are processed by one or more appropriate Event Handlers.
  • Event Store: The place where the Events are stored. For our application, this will be a SQL database.
  • Command Interface: The application which accepts Commands. For our solution, this will be an ASP.NET Web API application.
  • Query Interface: The application which accepts Queries. Can be the same application that has the Command Interface. For our solution, this will be an ASP.NET Web API application.

That's a lot of classes we need to build! Thankfully, there is a NuGet package out there which makes this entire process much simpler: SimpleCQRS.

SimpleCQRS implements a Command Bus, Event Bus, and hooks via which we can define out Commands, Events, Command Handlers, Event Handlers, Domain Objects, and Event Store. Its GitHub repository is here, though there isn't a lot of good documentation on it. Even so, we can start defining our Domain Objects using classes and interfaces generated by SimpleCQRS.

Domain Objects

We're going to use a simple architecture for this application, with the following domain objects:

  • Movie: Represents a Movie, with properties for the title, running time, and release date.
  • Movie Review: Represents a Review of said Movie, with properties for the review content, publication, and writer of the review. One Movie may have many Reviews, but one Review only corresponds to one Movie.

This results in a normalized database that looks like this:

(Remember that this database represents the Query side of our application, not the Command side.)

From this model, we can create domain objects that look like this:

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() { }

    public Movie(Guid movieId, string title, DateTime releaseDate, int runningTimeMinutes)
    {
        //Implementation done in Part 2
    }
}

public class MovieReview : AggregateRoot
{
    public string Content { get; set; }
    public string Reviewer { get; set; }
    public string Publication { get; set; }

    public MovieReview(Guid reviewId, string content, string reviewer, string publication)
    {
        //Implementation done in Part 2
    }
}

Note that Movie inherits from something called AggregateRoot. AggregateRoot is a class implemented by SimpleCQRS that implements a GUID key and represents a model of an object. (The term "Aggregate Root" is borrowed from Domain-Driven Design). In essence, an Aggregate Root is any Domain object that can be uniquely identified from all other Domain objects.

NOTE: SimpleCQRS restricts all Aggregate Roots to using a GUID as their key; no integer implementation is available.

Now that we've got our Domain Objects defined, we can start to define what kinds of Commands we can accept and how we handle them, and we will do so in Part 2 of this series, which covers creating and handling Commands and Events. If you'd like to see the code I built for this series, check out the GitHub repository.

Happy Coding!