I've been using your blogs that you did on ICommand/IQuery patterns as a guide to develop my domain and facilitate communication between layers.
I've run into where I need to contain a group of command handlers that will perform the following workflow:
- EmailCommandHandler (saves to DB that this action was taken by the user)
- EmailService.Email (if the transaction succeeded, send the email)
This appears to be a saga container. Any suggestions with SimpleInjector or going back to your blog about ICommand/IQuery patterns how this could be restructured or what you've done in your projects.
I have absolutely enjoyed employing your patterns and the way SI simplified orchestrating these patterns, so I'm hoping to continue with your suggestions.
Apr 22, 2013 at 4:17 PM
These classes don't really seem like command handlers to me:
- The ValidateEmailCommandHandler looks like some validation logic, simply the precondition of the command handler to run. It might be better to give it its own architectural element. For instance, you can define a IValidator<T> abstraction and that
validation class can implement IValidator<EmailCommand>.
- The EmailCommandHandler itself sound like it is reused by multiple other pieces of business logic (called by other command handlers). In my experience it is best not to wrap command handlers in other command handlers. Let a command be atomic. Any reused
functionality can be put in a service (such as IMailSender) that you inject into the handlers.
- Sending mails after a db transaction committed, does sound a bit like a model with
Domain Events. Handling (business) events is similar to commands (with a common IEventHandler<TEvent> abstraction), but it would be quite natural to have multiple event handlers handling a single event. In your case you could fire a
UserActivatedEvent from within an ActivateUserCommandHandler and this could trigger
SendUserActivationMailEventHandler and InformBillingAboutActivatedUserEventHandler classes. I haven't written anything (yet) about Domain Events on my weblog, but perhaps
this article is interesting to you. It's hard to say if Domain Events are interesting for your project, but it's worth doing some research on.
Apr 23, 2013 at 8:54 PM
Edited Apr 23, 2013 at 9:05 PM
Definitely have been reading on Domain Events and I believe they would be a nice addition for extra responders (emailing, logging, auditing, etc) to certain domain events.
I've trying to see how I can integrate in a IOC centric way and it looks like if I followed the defacto blog that a lot of these other articles have been based off it seems there is the static class I'll need to have in my concrete implementations.
You provided an answer to this very thing and recommend a possibility of a method injection.
Now with my scenario I'm going to provide some more detail as the items seemed a bit misleading now that I look at it:
The scenario I'm working on:
User selects an incident that they want to email. The process for this command requires the following:
- Perform user authorization (Validation?) that they have access to the incident
- Create a report (PDF) of this incident
- Email the report
- all successful then create a history log that this incident was emailed by this user
- fail, inform user (permission, service down, generic retry)...
With the pointers to domain events, I am very interested in providing that functionality, so my code work flow would be like so:
- TransactionDecorator pattern // (you blogged about this, in case anything fails, the data will roll back)
- ValidatorDecorator pattern // (you blogged about this, with IValidator<IncidentEmailCommand>... this checks for permissions)
- IncidentEmailCommandHandler.Handle(...) // handles the generating the incident report, so will have IReportService, IEmailService
- IEmailService.emails and then calls the DomainEvents.
- IEventHandler<IncidentEmailCommand>.Handle... will handle the logging since at this point everything is assumed as successful.
So, if to integrate domain events capabilities, and somehow avoid the static DomainEvents manager class, any thoughts?
Looking at the article you send, it appears he injects his CommandDispatcher or (DomainEvents manager) class into his Domain entity. I might go that route, and set my lifetime scope as singleton with SimpleInjector
Apr 24, 2013 at 9:43 AM
Prevent having a static class, because this makes unit testing simply much harder. I have yet to encounter a situation where using a static class like 'DomainEvent' is actually better. Mark Seemann has
an interesting article
about this as well.
Consider generating the incident report after the transaction, triggered after the business event was raised. Consider doing only the core work in the command + triggering the domain events. Everything that doesn't have to be done right that second (because
there are no consistency needs) or are heavy operations such as sending mails, doing intensive calculations, notifying other systems, generating reports, etc, can (or perhaps even should) be done in event handlers. Jonas Gauffin has an
about what to do in command handlers and what in event handlers. Again, I don't agree about using the service locator / ambient context pattern for sending events (and I don't mind when commands return some data), but his article is
very informative. A must read.