Wednesday 27 April 2011

Domain Events

We recently trialled using domain events in one of our .net applications. Domain events are basically a simple way to delegate functionality to allow you keep you code clean.

The most common use is for you to raise an event which will send an email after completing some action, but there are many more uses.

First we have a class that will handle all ensure any events for a particular action (TEvent) are processed.

 public class EventNotifier : IEventNotifier  
   {  
     public void Notify<TEvent>(TEvent @event) where TEvent : class, IDomainEvent  
     {  
       var handlers = DependencyInjector.Instance.GetAllInstances<IHandle<TEvent>>();  
       foreach (var handler in handlers)  
       {  
         handler.Handle(@event);  
       }  
     }  
   }  

All of the events for a given action will implement a simple marker interface called IHandle and by using generics we can inject the events at runtime.

 public interface IHandle<in TEvent> where TEvent : class, IDomainEvent  
   {  
     void Handle(TEvent @event);  
   }   

An event is effectively just a model which we create and pass into our event notifier.

 public class FeedbackSubmitted : IDomainEvent  
   {  
     public Feedback Feedback { get; private set; }  
     public FeedbackSubmitted(Feedback feedback)  
     {  
       Feedback = feedback;  
     }  
   }  

The class that performs the action for a given event is pretty simple. It just needs to implement the Handle method for the given type (event - which is just a class!).


 public class OnFeedbackSubmittedSendEmail : IHandle<FeedbackSubmitted>  
   {  
     private readonly IEmailTemplateRepository m_emailTemplateRepository;  
     private readonly IFeedbackEmailSettings m_mailSettings;  
     private readonly IMailService m_mailService;  
     public OnFeedbackSubmittedSendEmail(IEmailTemplateRepository emailTemplateRepository, IMailService mailService, IFeedbackEmailSettings mailSettings)  
     {  
       m_emailTemplateRepository = emailTemplateRepository;  
       m_mailService = mailService;  
       m_mailSettings = mailSettings;  
     }  
     public void Handle(FeedbackSubmitted @event)  
     {  
       var template = m_emailTemplateRepository.GetFeedbackTemplate();  
       if (template != null)  
       {  
         var feedback = @event.Feedback;  
         var message = template.CreateMessage(new MailAddress(m_mailSettings.FeedbackEmailTo),  
                                 new Hashtable  
                                   {  
                                     {"dateSubmitted", feedback.Posted},  
                                     {"firstName", feedback.FirstName},  
                                                    {"lastName", feedback.LastName},  
                                     {"email", feedback.EmailAddress},  
                                     {"phone", feedback.PhoneNumber},  
                                                       {"comment", feedback.Comment}  
                                   }  
           );  
         m_mailService.SendMail(message);  
       }  
     }  
   }  

So once we have set all this up, we can continue to add actions for the event without modifying our core business logic. It allows us to avoid having our services becoming very cluttered.

No comments:

Post a Comment