Lets take a scenario where an Order is dispatched and optionally a mail can be sent to the customer depending on an attribute in the Order class. The functionality to send an email is in a service "EmailService".
My question is should the Order.Dispatch method call the EmailService to send the email depending on the attribute in the Order class or should the application layer after calling the Order.Dispatch method call the EmailService? Which is the correct way to do this in DDD?
Thank you.
NN
Domain events allow you to decouple concerns. As soon as an order is dispatched, it could raise a domain event informing interested subscribers. This allows you to make the decision to send an email somwewhere else, so that the order aggregate can remain pure. It often also helps to capture the language better; when an order is dispatched, send an email.
public class Order
{
public Order(string id)
{
Guard.ForEmpty(id, "id");
Id = id;
}
public string Id { get; private set; }
public void Dispatch()
{
DomainEvents.Raise(new OrderDispatchedEvent());
}
}
public class MailService : IHandle<OrderDispatchedEvents>
{
private readonly IMailSender _mailSender:
public MailService(IMailSender mailSender)
{
_mailSender = mailSender;
}
public void Handle(OrderDispatchedEvent #event)
{
_mailSender.Send(...);
}
}
I would keep that on the application service layer. The sending bit may be simple enough in the Order.Dispatch as you could pass in an instance of the service but how about first of all composing the e-mail? That is probably somewhat more tricky.
Placing it in the operation script in some application service layer task is one way. You could also respond to a domain event (OrderDispatched for instance) and then send. Another option (when using a service bus) is to publish the OrderDispatchedEvent and have you Order endpoint subscribe to that and then send a SendEMailCommand to the E-Mail endpoint.
But I would not try to handle the sending in the domain itself as it feels more like output generation as opposed to some business operation/calculation that the domain is typically involved with. It is a business requirement but just on another level in the same way reporting works. Although business-related, or process related, it does not necessarily belong in the domain.
Just my ZAR 0.02 :)
DDD is not a recipe so there's no correct way to do something.
If by Dispatch you mean that the Order is on the way to the customer (hint: perhaps more accurate semantics are needed here) then the Application layer which sets the Order status as Dispatched can also ask a NotificationService to notify the customer.
I believe that a Domain Event approach is the best though, so once the Order has been dispatched, the OrderDispatched event will be published and a notification service could subscribe to it and will notify the customer using the EmailService, SMSService etc
But the Order itself has nothing to do with this. Some other domain object decides when an Order should be dispatched, it sends a DispatchOrder command to a Domain service which will do the dispatching and then it will generate the OrderDispatched event. This means that your Order shouldn't have a Dispatch method as it's not the Order that does the dispatching. A simple Status property is enough.
Related
I would like to secure my rest endpoints in the backend. For example an author can query his books like this:
/books?authorId=5&login=username
#GetMapping("/books")
#Timed
public ResponseEntity<List<Book>> getAllBooks(
#RequestParam(value="authorId", required = false) String authorId,
#RequestParam(value="login", required = false) String login) {
if(!login.equals(SecurityUtils.getCurrentUserLogin().get())){
return ResponseEntity.status(401).build();
}
List<Book> result;
if(authorId!= null)
result = bookService.findByAuthorId(authorId);
else if("admin".equals(SecurityUtils.getCurrentUserLogin().get()))
result = bookService.findAll();
else return ResponseEntity.status(401).build();
return ResponseEntity.ok().body(result);
}
Preferable I would like to only pass the authorId in the params
/books?authorId=5
but since SecurityUtils only gives me the loginName I can't compare them and identify the user in the backend.
Also since it's a microservice I can't access the AccountService.java which is handled by the gateway.
It all works fine but it seems wrong? Is there a better way to allow certain querys only for certain users? Should I make another rest endpoint which handles specifally requests to get books for specific users?
Thank you
You are addressing 2 use cases: one for authors (list my books) and one for management (list all books) for security reasons but usually you may also want to return different data based on use case. It could be a good idea to have 2 different resources: /api/my_books for authors and /api/books for management, you could even use nested resources.
For returning different data (also for security reasons) you can use the DTO option of JHipster with a service layer to map them from entities rather than exposing entities in your REST controllers.
Also don't pass the user id as a request param, you should modify TokenProvider to add it to the token as a claim. If you don't want to add user id to the token, you should modify book entity in your service so that it references user login rather than internal id, as long as it is immutable it does not make a difference.
Within my application service, I have the following code for publishing domain events:
var document = await dbContext.Documents.GetAggregateAsync(message.DocumentId);
publisher.SubscribeTo<DocumentOwnerChanged>()
.UsingDelegate(
async a => await messageGateway.DocumentOwnerChanged(1, 1, 1));
document.ChangeOwner(message.OwnerId);
await dbContext.SaveChangesAsync();
await publisher.Publish(document.ReleaseEvents());
I'm trying to decide if I like having this knowledge of publishing events within the app service or if I should externalize this somewhere up higher in the root.
thoughts?
You would typically register handlers in the Composition Root, unless you had to dynamically register and un-register handlers based on other messages.
There is some discussion around this here
You would publish domain events typically in your domain layer:
public void SomeDomainBehaviour()
{
// do something domain-y
DomainEvents.Publish(new DomainEvent());
}
Jimmy Bogard discusses other ways of publishing Domain Events here
In my project, there is a concept of user A sending a FriendRequest to user B. In a simplified version, the request looks like this:
class FriendRequest
{
long Id;
int UserId;
int OtherUserId;
string Message;
}
In the Accept method, I need to check whether the current authenticated user equals the OtherUserId in the FriendRequest. The currentAuthenticatedUserId is passed from the controller down to the application service. Now, the question comes that whether I should do the check in the application service or in the FriendRequest aggregate root.
//In application service code:
if(currentAuthenticatedUserId !=friendRequest.OtherUserId)
{
throw new FriendRequestException("Can only accept friend requests sent to you");
}
friendRequest.Accept();
vs.
//In application service, but we are not checking it here.
friendRequest.Accept(currentAuthenticatedUserId); //The check is done inside `FriendRequest` and the exception is also thrown there.
Access control is one of the main responsibilities of application services.
So check the user ID in the app service, not in the entity.
friendRequest.Accept(...)
What does it mean in the domain terms? The request accepts itself or what does it accept? I believe, you need to expand your ubiquitous language with more verbs that correlate to nouns.
As an example, I might think of "a person can accept a friend request that was sent by another person". In this case you would have a person.Accept(friendRequest). It will then be the service responsibility to fetch the Person based on the current authentication details.
I am in the process of making a web service and would like to apply domain patterns to it. I am having problems making my domain entities have more behavior. I would like to do something like this
public void DoSomethingApi()
{
CustomerRepository customerRepository = new CustomerRepository();
Customer customer = customerRepository.GetCustomer("myId");
customer.DoSomething();
}
to make my customer entity have more behavior I have tried the following:
public class Customer
{
public void DoSomething()
{
// how do I do this?
// I need a repository and a bunch of services todo work here
}
// using double dispatch
public void DoSomething1(DoSomethingService service)
{
service.DoSomething();
}
// using domain services directly
public void DoSomething2()
{
new DoSomethingService().DoSomething();
}
// using event broker and domain events
public void DoSomething3()
{
EventBroker.FireEvent<DoSomethingEvent>();
}
// using Actions
public Action DoSomethingAction4 { get; set; }
}
All methods have pros and cons, but I liked the use of domain events the most. However how do you return a value with domain events? how do you handle rollbacks if the method is in a transaction?
or maybe domain events is really just for notification (fire and forget)...
From how I understand and practice it, a domain event is something that already happened. (In our convention, the event names are always in the past tense). Publishing a domain event just "let's the world know" that something happened. Any event listeners then act accordingly independent of what caused the event. The event carries information of what happened It does not return anything.
As such, a domain event cannot be rolled back. A transaction inside a listener that gets triggered can be rolled back but not the event itself.
Edit: It is as you mentioned - fire and forget.
I'm still fairly new to DDD applications. I'm reading Eric Evan's "Domain Driven Design" and have read Employing the Domain Model Pattern by Domain Events Salvation by Udi Dahan...
One thing I can't make out though is how should information about the successful or unsuccesful completion of Domain Events be returned as feedback to the user (i.e. UI Layer)?
For example, we could have the following Application Layer code:
// Application Layer
public void SubmitOrder(OrderData data)
{
var customer = GetCustomer(data.CustomerId);
var shoppingCart = GetShoppingCart(data.CartId);
customer.Purchase(shoppingCart);
}
// Domain Model
public class Customer
{
public void Purchase(ShoppingCart cart)
{
// something done with the cart...
DomainEvents.Raise(new CustomerPurchaseCompleted() { Customer = this, ShoppingCart = cart });
}
}
Now let's say we have the following event handler that sends a confirmation email to the customer if the customer has an email address specified.
public class CustomerPurchaseCompletedHandler : Handles<CustomerPurchaseCompleted>
{
public void Handle(CustomerPurchaseCompleted args)
{
if (args.Customer.Email != null) {
// send email to args.Customer
}
else {
// report that no email will be sent...
}
}
}
My question is: How should I "bubble up" a feedback message to the UI layer saying that no email will be sent because the customer doesn't have an email set?
The options as I see them today are along the lines of:
Have the UI layer check if the Customer has an email and react accordingly with a message. This seems bad since the UI would be aware that an email is supposed to be sent, which is a application level information.
Throw a UserHasNoEmailException when no email is present and catch that information somewhere. That's really bad because exceptions should not be used to return information, plus it's not a fatal error and should not abort other handlers...
Have SubmitOrder() return some List<FeedbackMessage>. This would require changing the Purchase() and DomainEvents.Raise() methods to also return this list. This leads to the Domain Model knowing what the UI should of should not display...
Neither of these three options seems really good and practical. So how do DDD experts do it?
Thanks.
Another option you have is to implement another event handler which is specifically responsible for notifying the UI that a customer doesn't have an email address. So where CustomerPurchaseCompletedHandler doesn't send an email, this handler would notify the UI. This handler would be part of the UI layer. A good way to notify the UI would be to inject an event aggregator into this handler:
public class NotifyingCustomerPurchaseCompletedHandler : Handles<CustomerPurchaseCompleted>
{
public IEventAggregator Events { get; set; }
public void Handle(CustomerPurchaseCompleted args)
{
if (args.Customer.Email == null) {
// notify UI
this.Events.GetEvent....
}
}
}
Overall, this is essentially approach 1. True, the UI layer is now aware that an email is to be sent, however the UI has to have that knowledge regardless because it needs to render a message stating that no email is to be sent. Display a message is a UI concern and by leaving the handler implementation as part of the UI layer you keep it as such. The problem with this approach is that you are checking whether the customer has an email twice. Additionally, the sending of an email is not directly tied to the UI notification.
Another option is to introduce another event to indicate that a purchase was completed for a customer that doesn't have an email. The UI could then subscribe to this event. The downside of this approach is that you are creating an event specifically for a UI requirement not to express domain knowledge.
Events should not report feedback. Events ARE feedback.
In this case the Email is a business requirement. So the customer.Purchase(shoppingCart); should really throw an exception if the email has not been specified.
But let's say that the actual email delivery fails. What I usually do is to create a domain model which I use for notifications. so I do this:
var notification = new Notification(userId, "Failed to deliver receipt to user.");
notificationRepository.Save(noitification);
Which in turn would generate a NotificationCreated event which can be picked up by the UI.