Domain Events Made Easy with JaySmith.DomainEvents

Today I want to present a new library that I have developed to ease the implementation of domain events in my current projects.  This is largely based on Udi Dahan’s blog series on domain events.   This blog will be a walk through of how to add the library to a console application, create a domain object, domain event, domain event handler and raise the event.  My goal is to make adding support for Domain Events to an application easy so you can spend more time working in the problem domain not wasting time wiring up infrastructure.

Steps to getting this working:

  1. Add Domain Events package for StructureMap to application
  2. Create Bootstrapper class to initialize StructureMap
  3. Create a Domain Object
  4. Create Application class to contain our main application logic
  5. Define a Domain Event
  6. Define a Domain Event Handler
  7. Raise the Event

Create New Console Application

Open Visual Studio and create a new Console Application targeting .NET 4.0/4.5.

Add the JaySmith.DomainEvents.StructureMap package via nuget.  This will install all necessary dependencies including StructureMap.  StructureMap is my IoC of choice.  I will be doing a future post on how to use JaySmith.DomainEvents with your IoC of choice.


Create Bootstrapper to initialize StructureMap

   1:  public static class Bootstrapper
   2:  {
   3:      public static void Initialize()
   4:      {
   5:          ObjectFactory.Initialize(x => x.Scan(scan =>
   6:              {
   7:                  scan.TheCallingAssembly();
   8:                  scan.WithDefaultConventions();
  10:                  scan.AssembliesFromApplicationBaseDirectory();
  11:                  scan.LookForRegistries();
  13:                  scan.ConnectImplementationsToTypesClosing(typeof (IDomainEventHandler<>));
  14:              }));
  15:      }
  16:  }

Most StructureMap users will not that for a default configuration lines 7 and 8 are all that are usually required.  Domain Events uses Common Service Locater to do resolution for finding implementations of event handlers and the Domain Events StructureMap package contains a registry that needs to be loaded.  So lines 10 and 11 tell StructureMap to load assemblies in the base directory which is where the JaySmith.DomainEvents.StructureMap.dll will be and then it tells it to look for registries.  This will allow the library to wire up the StructureMapAdapter for Common Service Locator.  You don’t have to understand how this works to utilize the library.  I just wanted to point out why the extra configuration is needed.

Line 13 is also required, it tells StructureMap how to locate instances of IDomainEventHandler<T>.  This will make more sense when we start creating the handler.  I am looking for a way to move this to my StructureMap registry to it doesn’t have to be manually added here.  If anyone knows how to do that drop me a line.

Create a Domain Object

Let go ahead and create a domain object for our application.  We are going to have a Person object that looks like the following:

   1:  public class Person
   2:  {
   3:      public Person(string firstName, string lastName)
   4:      {
   5:          FirstName = firstName;
   6:          LastName = lastName;
   7:      }
   9:      public string FirstName { get; set; }
  10:      public string LastName { get; set; }
  12:      public string FullName
  13:      {
  14:          get { return string.Format("{0} {1}", FirstName, LastName); }
  15:      }
  16:  }

We need to model the behavior that is interesting to our application.  We are going to be interested in when someone changes their last name.  This can happen for any number of reasons and our system want to be able to handle that.  So let’s add a method to allow us to change the last name.

   1:  public void UpdateLastName(string newLastName)
   2:  {
   3:      LastName = newLastName;
   4:  }

This may seem a little over simplified but we will be adding more code to this method shortly.

Create Application class to contain our main logic

Now that we have a Person object and we want to change the last name of a user in the system we need to write the code to do that.  Here I want to create a class to encapsulate the application logic.

   1:  public class MyApplication
   2:  {
   3:      public void Run()
   4:      {
   5:          var person = new Person("Kristina", "Parker");
   6:          person.UpdateLastName("Smith");
   7:      }
   8:  }

Here we see that we have a person “Kristina Parker” who for whatever reason, in this case she married me Winking smile, changed her name to “Smith”.  Our code reflects this change by calling the UpdateLastName method.  This keeps our domain object up to date, but what if other parts of the system need to do something when a Persons last name changes? 

We could put that logic in the UpdateLastName method but over time this method would get very long and hard to maintain.  It also doesn’t help us keep with SRR (The Single Responsibility Principle).  I would be awesome if we could just raise an event that the last name has changed and those other things just happened.  This is where the domain event comes in. 

Before we do that we need to wire up our MyApplication class in out program main so our application actually executes.

Your Program class should like the following:

   1:  public class Program
   2:  {
   3:      public static void Main(string[] args)
   4:      {
   5:          Bootstrapper.Initialize();
   7:          var app = ObjectFactory.GetInstance<MyApplication>();
   8:          app.Run();
  10:          Console.Read();
  11:      }
  12:  }

Here initialize our IoC with Bootstrapper.Initialize() and then we get an instance of our application class and then call run.  If we build and execute the application at this point it will execute just fine, the person object will be created and the last name will change.  Now we want to create that domain event so we can notify other parts of the system that something interesting has happened.

Define a Domain Event

The Domain Event is responsible for modeling any information that an Domain Event Handler might need to do its job.  Here is the PersonLastNameChangedEvent:

   1:  public class PersonLastNameChangedEvent : IDomainEvent
   2:  {
   3:      public Person Person { get; set; }
   4:      public string OldValue { get; set; }
   5:      public string NewValue { get; set; }
   7:      public PersonLastNameChangedEvent(Person person, string oldValue, string newValue)
   8:      {
   9:          Person = person;
  10:          OldValue = oldValue;
  11:          NewValue = newValue;
  12:      }
  13:  }

The class implements the IDomainEvent interface.  This is necessary for the Domain Events library.  I usually provide an instance of the object that has changed to allow handlers to have full access to any information they may need.  I also like to provide the old and new values of what changed and providing a constructor just eases the creation of the object.   There is no requirement on how you name the class for the event but I recommend using a name that represents what happened in the system.  In this example we used the name of the class the event occurs in and then the name of the event.  This allows you to quickly see where this event actually gets raised; When the LastName is changed on the Person object.

Define a Domain Event Handler

Now that we have have a Domain Event there needs to be something that can handle that event when it occurs. 

   1:  public class PersonLastNameChangedHandler 
   2:              : IDomainEventHandler<PersonLastNameChangedEvent>
   3:  {
   4:      public void Handle(PersonLastNameChangedEvent args)
   5:      {
   6:          var oldLastName = args.OldValue;
   7:          var newLastName = args.NewValue;
   8:          var fullName = args.Person.FullName;
  10:          Console.WriteLine("Last Name changed from {0} to {1}",
  11:                  oldLastName, newLastName);
  12:      }
  13:  }

To implement a Domain Event Handler for the PeronLastNameChangedEvent we create a class that implements IDomainEventHandler<PersonLastNameChangedEvent>.  You can have more than one class that handles this event.  IDomainEventHandler has one method that must be implemented named Handle. 

The Handle method is pasted an instance of IDomainEvent that represents the Event that was raised.  In this case it is an instance of PeronsLastChangedEvent.  As you can the handle has full access to any information contained in the DomainEvent class.

In this example we write out a message to the console, your handler will probably do much more interesting things than this.  I hope you are starting to see how powerful this can become.

Raise the Event

We have created a Domain Object, Defined a Domain Event, and created a Domain Event Handler but the event still isn’t firing.  We have add the code to actually raise the event. 

To raise the event when the Persons last name changes we want to modify the Person.UpdateLastName method to to the following:

   1:  public void UpdateLastName(string newLastName)
   2:  {
   3:      var oldLastName = LastName;
   4:      LastName = newLastName;
   6:      var lastNameChangedEvent = 
   7:          new PersonLastNameChangedEvent(this, oldLastName, newLastName);
   8:      DomainEventManager.Raise(lastNameChangedEvent);
   9:  }

We have added line 3 to capture the current LastName before we change it.  In line 6 and 7 we instantiate the PersonLastNameChangedEvent providing the required information.  Finally on line 8 we use the DomainEventManager to raise the event.

Executing the code now will raise the event and you will see the message from the Event Handler printed into you console window.


I hope this walk through gives you a good feel of just how easy it is to add Domain Events to an application.  If you have any questions, critics, or suggestions please do not hesitate to contact me.  If you run into any issues please log them on the project site located on github.  The source code is also available there and I do accept updates from the community.


<<  October 2014  >>

View posts in large calendar

Month List