Milan I am really looking forward to a full course from you, building an entire application with DDD, Rebus, RabbitMQ etc etc. I hope you will make one! Great video btw!
Speaking about trying to saving entity and domain events together, that is why I prefer using event sourcing :) you deal only with domain events and rebuild entities based on them.
@@MilanJovanovicTech But man, please, beare with me. You are telling your audience to store events with EF Core and then develop a full backround service that polls for events tand tries to publish somewhere else... how is that easier than simple go event sourced and use something like EventStoreDB to handle persistence, and subscription of events?
Thank you for the insightful breakdown of domain events and their role in decoupling systems! I’m curious about your thoughts on the Outbox pattern versus traditional transactional methods, particularly in terms of scalability and complexity in distributed systems. How would you approach balancing these trade-offs in a large-scale microservices architecture?
After watching couple times, im still left with impression that nothing changed from start to end, we are still raising event after we saved changes to the DB except at start, specific event was raised in domain layer probably scattered and at end all events are raised by iterating events in the persistence/infrastructure layer. at both times we would throw any exception in the events back to the UI/calling layer. Am i missing something? Effectively the title of the video is achieved in a way but the drawback still exist. i think the drawback is true for any in memory event bus.
Hi, Milan! This is clear for use cases where you invoke methods on the aggregate root, such as create() or addItem(), where you can publish the corresponding event inside the entity producing it, but how would you approach an OrderDeletedEvent? Would you need to pass through a delete() method or something alike?
Hi Milan, perfect timing; I was just introducing DomainEvents to an otherwise Clean Architecture yesterday. Pretty much as you present it. However, a consideration: One of my events is change of State and I was debating with myself whether I should have a StateChangedDomainEvent or multiple like StateChangedToAuthorized, StateChangedToTerminated etc. I guess "it depends", but do you have any thoughts you'd like to share?
I'd say it depends on how you handle it? Also, the State is obviously a part of a larger object/entity/aggregate. Maybe OrderState? So it should be OrderAuthorized/OrderTerminated more so than StateChanged
Really like your content and views on real world architectural challenges. Isn”t this specific approach creating a dependency on MediatR in your domain model? I consider this a framework dependency that I would avoid.
Create your DomainEvent implementing INotification makes the Domain tightly coupled to MediatR and any changes to MediatR affect your domain and I think it is not a good practice but I could be wrong
I prefer being practical rather than dogmatic. What could possibly change with MediatR? Will pub-sub become unpub-unsub? (sorry for being ironic, but 😅)
Very clear video as always, thank you! Generally speaking would it be better to not pass the cancellation token to _publisher.Publish ? By that I mean if the system has got as far as saving the changes to the database we do not want to allow it to back out of publishing the domain events.
Great video, thanks! Will there be more videos with the development of the E-shop web api? And will you add any new entities to the project? Product cart for example
I love your channel, it is extremely useful. I have a question. How it is possible to persist an event by ef core change tracking that was raised in the rich model while the snapshot pattern is used to map the rich model to a model that is supposed to be persisted into the database?
EF is tracking the "snapshot" model? And you're only using the rich model to execute your business logic? I'd build some IOutboxService that would just take the rich model, and create the require domain events. Or you can figure out a way to do it while mapping back to the snapshot model.
@@MilanJovanovicTech Thank you for your response. Yes I am using only my rich model to track the respective business logic and when I want to store any result to the database, I map the rich model to a snapshot model. So, any events that were raised inside of rich model, will be missed by ef core change tracker.
thank you for a nice video, I have a question regarding using the MediatR in the domain layer. i kknow that that domain layer should not have any integration with other libraries, can you please explain why in your case you use an external library ? I would appreciate your answer.
Another question please what do you mean by 'Atomic' in the latest approach, Do you mean that we will either persist the business logic and the event in the db or if there is any problem then we will rollback the business logic and also the event ?
I am not really a fan of publishing integration-events inside domain-event handlers. I think it's better to have a clear separation between the domain- and integration-events. Domain-events are handled as a part of the transactions and integration-events are published after the transaction has completed. It still does not fix the problem where publishing the integration-events fails but you could always switch to using outbox pattern. How about this? // Application layer class DomainEventHandler { public DomainEventHandler(DbContext dbContext) { ... } public Handle(SomeDomainEvent event) { var someEntity = this._dbContext.GetSomeEntityBy(event.Data); someEntity.Update(event.Data2); someEntity.RaiseIntegrationEvent(new SomeIntegrationEvent()); } } And inside SaveChanges() publishDomainEvents(); base.SaveChanges(); publishIntegrationEvents(); Domain-events are published inside domain layer and integration-events are published in the application layer. Domain-events handlers can be a part of the transaction and integration-events are published after the transaction has completed.
Question. I have a CreateSomethingAHandler and during this handler, my domain has raised an event. So I will have AEventHandler. During AEventHandler, can this AEvent raise another Event? like a chair event? Does it sound like bad practice? CreateHandler -> Domain raise an event-> EventHandler-> Domain can Raise another EventHandler?
In general - it's not a bad practice. But I would definitely consider using an Outbox. Chaining so many domain events can lead to a pretty large transaction.
Hi Milan! I have one question. When we are removing a line item, this is done by a function inside the aggregate root Order. So we can call the function Raise passing the LineItemRemovedDomainEvent. How would be the approach to an aggregate root deletion (ex: Order)? We would have to expose the Raise function and call it from the handler? Thanks.
@@MilanJovanovicTech This method would be responsible just for raising the event? What would prevent a programmer from deleting the aggregate root without calling this method? Thanks for the answer.
Hi Milan, Thx again for nice introduction to domain events! 1. Is implementation of the Application's OrderCreatedEvent.cs: internal record OrderCreatedEvent(Guid Id); or we need something more? 2. May I ask for the name the VS theme that you're using. Very simple and nice one.
@@MilanJovanovicTech Thx for answering!!! I'm using VS17.5.5 default dark theme but am not using Resharper. Difference might be there. I have to install some version of Resharper although VS has a lot of builtin features regarding helping in coding already. Thx. again!
Hi, Milan. I want to ask you to create a video about Cancellation token. I know what is it, but I'm interesting in situation there I have to implement the cancellation callback for production. This thing possibly the most frequently used element and a lot of developers actually don't understand how to use it. (As am I actually😅). I'm coming to read.
So..... Everything is possible to implement without MediatR. And it will have exactly the same behavior but without additional framework. Please correct me if I'm wrong.
Why is domain event publishing being implemented in ApplicationDbContext? Shouldn't this be implemented in UnitOfWork (of course, if you are using the pattern)?
I use id value objects for my domain entities. So I have something like public sealed class domainEntityName : Entity { ... }. My domainEntityNameId inherits from public sealed class UserId : EntityId { ... }. At min 10:41, where you grab the domain events from the changetracker, would I put something like ChangeTracker.Entries() ? The reason I ask is because when I try to obtain my domain events, I get zero count.
Hii 🖐 I watched your video on creating domain events, and I found it very informative. However, I noticed that your implementation seems to violate the principle that the domain should not depend on any dependencies.
@@MilanJovanovicTech I understand. I kind of thought about this like strong vs eventual consistancy. When you only communicate what was saved, then you are sure that what you communicate is the same as the persistant state.
what if i have domain events that change state of entities how this changes will save in database ? i think can solve this : await base.SaveChngesAsync(); // publish events await base.SaveChangesAsync();
like Homer would say, yesssss but nottt, it didn't like what i saw, why do you use context database and you don't create a repository o service to use data layer, you have datacontext on each handler, ummmm it looks bad
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
Milan I am really looking forward to a full course from you, building an entire application with DDD, Rebus, RabbitMQ etc etc.
I hope you will make one!
Great video btw!
It's coming in a few months! :)
Starting recording May/June
Thanks for asking , I was looking the same :)
@majormartintibor Course is nearly ready, coming out in a few weeks. I'm calling it "Pragmatic Clean Architecture"
@@rohit704 Coming out soon, pay attention to my newsletter for the launch
Speaking about trying to saving entity and domain events together, that is why I prefer using event sourcing :) you deal only with domain events and rebuild entities based on them.
If only it were as beautiful as it sounds 😅 There are many nuances with event sourcing that can be easily overlooked.
@@MilanJovanovicTech of course, it's not a silver bullet :)
@@MilanJovanovicTech But man, please, beare with me. You are telling your audience to store events with EF Core and then develop a full backround service that polls for events tand tries to publish somewhere else... how is that easier than simple go event sourced and use something like EventStoreDB to handle persistence, and subscription of events?
Clean and simple implementation, thanks for sharing with us.
You're most welcome
Hey Milan, really nice video. I'm looking forward for this new robust impl of the outbox pattern. Thanks for making such an awesome content, free.
Thanks, Wil :) I'll try to make it good 😁
You are the best man ... !! learning a lot from this collection of videos !! I feel my self like an expert in DDD ... hahaha
You rock!
I'm really liking your videos. Always clear and concise.
Thanks a lot, Alan :)
Looking forward to an indepth Outbox Pattern video. ❤
Recording it soon 😁
@@MilanJovanovicTech What will the difference be against your previous video about Outbox Pattern?
Hi Milan! Great video.
Is there any video in which you talk about integration events?
Thanks for the content.
Hmm, I don't think there is such a video (yet)
@@MilanJovanovicTech Looking forward for it 😀
Thank you for the insightful breakdown of domain events and their role in decoupling systems! I’m curious about your thoughts on the Outbox pattern versus traditional transactional methods, particularly in terms of scalability and complexity in distributed systems. How would you approach balancing these trade-offs in a large-scale microservices architecture?
The Outbox is there for temporal decoupling and reliably publishing messages - both of these are helpful in improving the scalability of a service.
After watching couple times, im still left with impression that nothing changed from start to end, we are still raising event after we saved changes to the DB except at start, specific event was raised in domain layer probably scattered and at end all events are raised by iterating events in the persistence/infrastructure layer. at both times we would throw any exception in the events back to the UI/calling layer. Am i missing something? Effectively the title of the video is achieved in a way but the drawback still exist. i think the drawback is true for any in memory event bus.
Yes, there's that drawback you noticed with this implementation. The Outbox pattern solves that issue
@@MilanJovanovicTech thank you for the information. so you planning to show that in coming in upcoming video?
@@empireofhearts Yes 😁
TQ Milan^^ 14:01
Thanks 😁
Hi, Milan! This is clear for use cases where you invoke methods on the aggregate root, such as create() or addItem(), where you can publish the corresponding event inside the entity producing it, but how would you approach an OrderDeletedEvent? Would you need to pass through a delete() method or something alike?
Yeah, that would get the job done. Just expose a method that raises an event inside.
Hi Milan, perfect timing; I was just introducing DomainEvents to an otherwise Clean Architecture yesterday. Pretty much as you present it. However, a consideration: One of my events is change of State and I was debating with myself whether I should have a StateChangedDomainEvent or multiple like StateChangedToAuthorized, StateChangedToTerminated etc. I guess "it depends", but do you have any thoughts you'd like to share?
I'd say it depends on how you handle it?
Also, the State is obviously a part of a larger object/entity/aggregate.
Maybe OrderState? So it should be OrderAuthorized/OrderTerminated more so than StateChanged
Really like your content and views on real world architectural challenges.
Isn”t this specific approach creating a dependency on MediatR in your domain model? I consider this a framework dependency that I would avoid.
Yes, but it's a tradeoff I'm willing to make for the benefit of simplicity
Lesser of two evils Indeed, i prefer the approach that is after and as some clean up
There's a way to fix though
@@MilanJovanovicTech will there be a video on that? Or did you already have the video posted?
Create your DomainEvent implementing INotification makes the Domain tightly coupled to MediatR and any changes to MediatR affect your domain and I think it is not a good practice but I could be wrong
I prefer being practical rather than dogmatic.
What could possibly change with MediatR? Will pub-sub become unpub-unsub? (sorry for being ironic, but 😅)
Very clear video as always, thank you! Generally speaking would it be better to not pass the cancellation token to _publisher.Publish ? By that I mean if the system has got as far as saving the changes to the database we do not want to allow it to back out of publishing the domain events.
That's a very valid concern
Can you please milan make a video about Threading , async and await and Parallel and multi-threading if you have time.
And Thanks for all your effort
Maybe, not my forte though
Btw water to ask, do you use domain events to communicate between aggregates much?
Yes, it's very powerful for triggering side effects within a bounded context
Great video, thanks!
Will there be more videos with the development of the E-shop web api? And will you add any new entities to the project? Product cart for example
I don't think so, for the time being
I love your channel, it is extremely useful. I have a question.
How it is possible to persist an event by ef core change tracking that was raised in the rich model while the snapshot pattern is used to map the rich model to a model that is supposed to be persisted into the database?
EF is tracking the "snapshot" model? And you're only using the rich model to execute your business logic?
I'd build some IOutboxService that would just take the rich model, and create the require domain events.
Or you can figure out a way to do it while mapping back to the snapshot model.
@@MilanJovanovicTech Thank you for your response.
Yes I am using only my rich model to track the respective business logic and when I want to store any result to the database, I map the rich model to a snapshot model. So, any events that were raised inside of rich model, will be missed by ef core change tracker.
thank you for a nice video, I have a question regarding using the MediatR in the domain layer. i kknow that that domain layer should not have any integration with other libraries, can you please explain why in your case you use an external library ? I would appreciate your answer.
It's just an interface, I can live with that
Another question please what do you mean by 'Atomic' in the latest approach, Do you mean that we will either persist the business logic and the event in the db or if there is any problem then we will rollback the business logic and also the event ?
Exactly that!
I am not really a fan of publishing integration-events inside domain-event handlers. I think it's better to have a clear separation between the domain- and integration-events. Domain-events are handled as a part of the transactions and integration-events are published after the transaction has completed.
It still does not fix the problem where publishing the integration-events fails but you could always switch to using outbox pattern.
How about this?
// Application layer
class DomainEventHandler
{
public DomainEventHandler(DbContext dbContext) { ... }
public Handle(SomeDomainEvent event)
{
var someEntity = this._dbContext.GetSomeEntityBy(event.Data);
someEntity.Update(event.Data2);
someEntity.RaiseIntegrationEvent(new SomeIntegrationEvent());
}
}
And inside SaveChanges()
publishDomainEvents();
base.SaveChanges();
publishIntegrationEvents();
Domain-events are published inside domain layer and integration-events are published in the application layer. Domain-events handlers can be a part of the transaction and integration-events are published after the transaction has completed.
I'd rather separate integration events from the main business transaction using an Outbox, it leads to a more robust implementation
Question. I have a CreateSomethingAHandler and during this handler, my domain has raised an event. So I will have AEventHandler. During AEventHandler, can this AEvent raise another Event? like a chair event? Does it sound like bad practice? CreateHandler -> Domain raise an event-> EventHandler-> Domain can Raise another EventHandler?
In general - it's not a bad practice. But I would definitely consider using an Outbox. Chaining so many domain events can lead to a pretty large transaction.
Hi Milan! I have one question.
When we are removing a line item, this is done by a function inside the aggregate root Order. So we can call the function Raise passing the LineItemRemovedDomainEvent.
How would be the approach to an aggregate root deletion (ex: Order)? We would have to expose the Raise function and call it from the handler?
Thanks.
Or create a method on the Aggregate root called "Cancel"/"Remove"?
@@MilanJovanovicTech This method would be responsible just for raising the event? What would prevent a programmer from deleting the aggregate root without calling this method?
Thanks for the answer.
Hi Milan, Thx again for nice introduction to domain events!
1. Is implementation of the Application's OrderCreatedEvent.cs:
internal record OrderCreatedEvent(Guid Id); or we need something more?
2. May I ask for the name the VS theme that you're using. Very simple and nice one.
1) Yes
2) I'm using native VS dark theme + ReSharper syntax highlighting
@@MilanJovanovicTech Thx for answering!!! I'm using VS17.5.5 default dark theme but am not using Resharper. Difference might be there. I have to install some version of Resharper although VS has a lot of builtin features regarding helping in coding already. Thx. again!
Hi, Milan. I want to ask you to create a video about Cancellation token. I know what is it, but I'm interesting in situation there I have to implement the cancellation callback for production. This thing possibly the most frequently used element and a lot of developers actually don't understand how to use it. (As am I actually😅).
I'm coming to read.
Got it!
So..... Everything is possible to implement without MediatR.
And it will have exactly the same behavior but without additional framework.
Please correct me if I'm wrong.
I'm only using MediatR to publish events and trigger the handlers. You can easily solve that without MediatR if you want to
Milan, can we store saga in MS-SQL apart from StoreInPostgres?
Yes you can
Why is domain event publishing being implemented in ApplicationDbContext? Shouldn't this be implemented in UnitOfWork (of course, if you are using the pattern)?
The ApplicationDbContext is the unit of work
Hello, how can i publish domain events if i have separate domain and database models?
Publish when mapping from one model to the other
Is the code available to download and practice?
I share the code on Patreon
I use id value objects for my domain entities. So I have something like public sealed class domainEntityName : Entity { ... }. My domainEntityNameId inherits from public sealed class UserId : EntityId { ... }. At min 10:41, where you grab the domain events from the changetracker, would I put something like ChangeTracker.Entries() ? The reason I ask is because when I try to obtain my domain events, I get zero count.
You'd be better off creating an IEntity interface, with the methods to get and clear domain events
ChangeTracker.Entries
@@MilanJovanovicTech Oh, that’s a great idea! Thanks! Your vids have helped me so much
Hii 🖐 I watched your video on creating domain events, and I found it very informative. However, I noticed that your implementation seems to violate the principle that the domain should not depend on any dependencies.
Should not depend on other layers
Why not only trigger the event when a save was succesfull? Then you would only communicate the persistant state.
It's not atomic
@@MilanJovanovicTech I understand. I kind of thought about this like strong vs eventual consistancy. When you only communicate what was saved, then you are sure that what you communicate is the same as the persistant state.
what if i have domain events that change state of entities
how this changes will save in database ?
i think can solve this :
await base.SaveChngesAsync();
// publish events
await base.SaveChangesAsync();
With the Outbox pattern, coming up :)
like Homer would say, yesssss but nottt, it didn't like what i saw, why do you use context database and you don't create a repository o service to use data layer, you have datacontext on each handler, ummmm it looks bad
You can extrapolate your own implementation from the example, that's good enough for me