1

slightly related to this question: Should I pass a repository to a domain object method that needs to fire an event after the methods actions have occurred and been persisted?

In this case the system needs to send emails of after the domain object's status is changed. Whilst unlikely, it could happen that the status change would not be persisted in which case the email should not be sent.

I could use a domain service to do the work, but all the logic of status changing belongs and is contained in the domain object so my services would end up looking like

 StatusService(Irepo repo) {

        void ChangeStatus(domainObject myObject, status newStatus) {
              try {
              myObject.ChangeStatus(newStatus);
              repo.Save(myObject);
              raiseEvent(new StausChangeEmailEvent(myObject))
              } catch { .. dont send email }
         }

Which id rather not do for several reason (one of which is there are now 2 ways of changing status only one of which sends the emails)

Id like to wrap it up in the Domain Method itself but this also doesn't feel right because I'm making the domain object responsible for its own persistence. (although I think I prefer it over the domain service way)

 class DomainObject() : IAggRoot {

 ...
 public ChangeStatus(irepo repo, status newStatus) {
    ..logic logic 
    this.Status = newStatus;
    repo.Save(this);
    raiseEvent(new StausChangeEmailEvent(myObject))
 }

 }

There's a bit of complications about the business logic, but really I'm interested how to fire events ONLY after the Domain Objects are persisted.

Edit: It is not so important if the email fails to send, it is important that an email is not sent if the status does not 'take' as senior people in the organisation people may receive invalid instructions in their mailbox..

Community
  • 1
  • 1
Joe
  • 1,327
  • 1
  • 10
  • 19

1 Answers1

1

It would be nicer to have consistent transactional behavior. You could commit events in the same transaction (queue or db), and dispatch from there. Anyways, if this is not what you're looking for, you could also have your aggregate record the event instead of having it raise it directly. This allows you to first commit your database transaction, and then to dispatch the event.

public interface IRecordingAggRoot {
     IEnumerable<IEvent> RecordEvents();
}

_repository.Save(aggregate);
_tx.Commit();
_dispatcher.Dispatch(aggregate.RecordedEvents());
JefClaes
  • 3,275
  • 21
  • 23
  • But where would this logic (the commit;dispatch;) live? The more I think about it the more I think 'service' - but where: application or domain service? Emails are a strong requirement from business tied to the status change operation, but the fact that the failure to send emails is (kind-of) acceptable muddies the waters a bit. Also, If I wrapped it in an application service that calls the changeStatus function on the domainModelObject I could have situations where developers call the chageStatus directly without using the service to ensure proper sequence of events. (internal to the rescue?) – Joe Mar 01 '14 at 23:43
  • OK, I understand now - took a bit for the penny to drop. The domain object builds up its collection of recorded events and the application layer program is responsible for processing any events after an error free commit(). I found this article helpful as well http://www.jayway.com/2013/06/20/dont-publish-domain-events-return-them/ – Joe Mar 19 '14 at 08:34