Get the source code for this video for FREE → the-dotnet-weekly.ck.page/cqrs Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
Milan, quick tip. Just write a semicolon after the namespace and it will convert them to file scoped. Also ctrl+R & ctrl+G will get rid of all unused using statements.
If you are using VS2022 you can also go into options and set up code cleanup to run on file save, set code cleanup to sort using and cleanup unused and to default the namespace to file scoped. Then you just have to Ctrl+S to apply a whole range of code formatting options that you can configure.
Or you edit the snippet from VisualStudio folder and remove usings, set the class public sealed by default (or internal). Now you don't have to clean the file each time you add a new file ;) it's worth the effort so much
This is pretty darn cool. Setup my own project and followed your instructions. I did have to dig through some of the other videos in the series, but I got everything working. I enjoyed your explanation. Your explanation was clear and easy to follow. Thanks for sharing.
From start it is not clear why you create interface for query and command. It is great that you learn and describe your material as well, it is good fast method. I would remove ApiController, additional inheritance, additional object in memory without any gains. Your own unit of work is anitpattern. EF already implement UoW in dbcontext object. Separate repository is also additional noise. Mediatr handler is independent implementation for single action. You make it depends on the common repository, which has many reasons to change. Also in my experience often repositories does not allow to reuse some logic. In different place the same repository action may require different transaction scopes, which repository does not address any way.
Query/Command interfaces make it more explicit and expressive than using IRequest for representing both concepts. In the end, it's the same thing underneath, I just prefer having a little bit more expresiveness.
Thank you Milan, I really enjoy your videos, you have clear explanations, straight to the point, no useless text that would make me move the video player's progressbar :)) keep going man.
Hi! Thanks for your work. I stumbled upon your channel and I'm enjoying. A suggestion: at the beginning you mentioned (3:06) you've already implemented the CQRS (kinda) but it is difficult to find where. I'd love to see since the beginning and it's not easy to find some order in youtube. I've taken a look in the playlist but it's not clear. I'll watch all your videos but it would be great if you have some list (maybe in video description) ordered, it'll be easier for new subscribers. Thanks a lot!!!
All this Clean, Super Clean architectural software design approach and this kind of video doesn’t say ‘You don’t need this huge complexity for your small to medium projects, or if you are a beginner’. If you just start your journey to software development road, skip this kind of ‘tutorials’ you will be overwhelmed and your brain will hurt. Just read the official documentation, make small applications, take your time. All this design principles and patterns are just tools that you will need on some, not all, projects. For small and medium projects this kind off approach will over complicate things. Trust me, you can build useful apps that don’t use any of this, keep them simple, stupid 🤪. I don’t say that this are not good at all, in big projects with big teams are a must, otherwise chaos will happen 😇. With time you will learn and figure out what and when you need to use it in order to accomplish your goal. Start small, learn the basics and build up your experience, otherwise you will lose precious time.
Let the viewers decide. I like to think everyone has some common sense in them to be able to critically view some concepts, and figure out if they make sense for them or not.
When giving an advice based on 30 years of experience has become a bad idea? What I said is my opinion and you, like a professional must respect other’s opinions. I didn’t said that everyone need to follow my advice or agree with me. I think that who wants to become a developer has the brain to decide. Please be open for debates, if don’t close the comments for your videos 🤓
Hey Milan, thanks for this great demonstration of CQRS. Could I maybe suggest a video idea where you show the full variation of the pattern? Including separate APIs, Read/Write models and Read/Write databases? All in combination with Mediator of course within the Clean Architecture & Domain Driven Design. I would be very interested in this. Thanks again for your valuabe content!
I prefer to write my own solution for cqrs instead of making abstraction for mediatr it's not so hard. I prefer stick query handlers close to dbcontext instead of inject repository there. I like your videos, Keep going! :)
Because it is simple to implement and relying on a package for simple implementations can be a problem for long running solutions. Watch the origin of CQRS there was never need of some library or framework, because it is trivial to implement.
Great Video! I cant get enough of your content. Can you explain a bit more about your Abstraction of Queries? As someone that primarily works with the data and DBA teams, I've seen a lot of different opinions on how queries should be handled to best balance performance, maintainability, and security.
The most performant approach would be create a small service per query handler, which will fetch only the data that is necessary to satisfy that query. For example, let's say I have a GetMemberByIdQuery and respective handler. In the video, I'm using a repository. An alternative would be to inject an interface like this: IGetMemberByIdSession Implement this interface in the Persistence project, however we deem fit. We can use EF, we can write a SQL query, etc. Does this make sense?
@@MilanJovanovicTech so in this scenario if you have a common behavior that you need in more than one handler, is it make a sence to make the IGet MemberByIdSession implementation inside the Persistence project and call it from both handlers?
I understand all of this, except - whats the point of CQRS from the software point of view, if you have only one storage anyway. It worked without ICommand/IQuery interfaces & handlers just as well. I recently spent some hours debugging our current project, where for some reason data was not saved to dabatase, only to found that I inherited some service from the wrong interface (naming in our project could be better...).
I like my Controllers to be dumb and short, so the requests they receive are the command parameter (or command itself) and the return is an AutoMapper mapped Dto. Every API endpoint boils down to a one-liner like return Mapper.Map(commandRequest) Which can, arguably, also be simplified with a generic type... Then I use Swagger/OpenAPI to generate the TypeScript models for the frontend to strongly-type glue the two layers together. One drawback of this approach is modifications towards the frontend; builds will fail if the commands/queries signature changes are not adapted on the UI layer, which is also a benefit as you deny yourself space for error, mistakes are immediately apparent, there's no space for deprecations and the client will only receive a working build with no compile errors.
Would be really interesting to see how to separate the storages to the read and write storage and how to sync them so the command will write to the `write` storage and reads will read from optimized `read` storage.
Separating read model and write model is foremost conceptual. You really need not to have separate implementations or even separate physical data storages-unless there is a requirement to do so. #yagni
Great video Milan, really enjoying these videos and there is always something I am learning. What are your views on vertical slice architecture in comparison to clean architecture?
Hey James :) Haven't used the vertical slice architecture ever, so I don't have any strong opinion on it. I don't mind it in general. But I prefer a layered architecture (like Clean) with stricter separation between concepts.
Great explanation! Could you please explain, is there any special reason to use records for Queries and commands and their results? While you use class for handlers. I know difference between class and record but I didn't find your idea.
I wonder which benefit you actually see here using MediatR (or messaging in general) over directly calling APIs on some interface? As you use specific command, query and response objects the coupling between the controller and the handler would be similar from my perspective. I would be interested in your arguments for this design choice. thx!
@@MilanJovanovicTech It is also simple to implement CQRS without it. But hey, with mediatR we also get to lose IDE navigation on our function calls, yay!
Milan, Does this pattern always define one handler for each single query or could you have a single interface that define several queries / command and one handler to handle them all? For example, let's say we have two queries related to the same domain entity. GetOrderById and GetOrderByMember does each will have a respective handler or can we implement one handler for both? Thanks in advance! Your videos are great and you explain it really well!
you have to register handler for each query command. They have different logic and should have dif implementation. I do not understand what really you mean to update logic you change one handler file.
Thanks for your great video... I have a question Why you didnt use mediatr' sender in your controller for run your commands and queries? You could inject mediater into your controller and use it
Good video as always. I just I've a question about the queries when they are simple. For example, in your case, you write an entire Command and CommandHandler just to do a simple GetById query. I know this is just an example, but to me, it's an overkill. So if I've do something like this in my code, usually, I inject directly the repository interface into my Controller and I execute the Query. I know this force you to make a dependency from the controller to the repository interface, but is a little cost to pay to don't write a lot of code for a simple GetById Query. It's just my opinion of course, but I want to know what do you think. As always, thank you for your videos! :)
Thanks for amazing video please can create example for singlr or hangfire in clean architecture I’m confused where we can put real time communication logic and again thanks very much ❤
Do you have a video where you teach approaches from scratch (as in from empty solution/project) ? This one is more like a part of follow-on series where you're just tweaking a bit inside an already completed full-fledged project.
@Milan Jovanović, I know this is a pretty old video, but can you please elaborate on how would you retrieve data in your command? Let's say before create a member you have first to retrieve some related data from DB. Will you create a query object inside you command handler? If yes - doesn't this break the idea of CQRS? My question is: sometimes we need to get data in order to write data. Where we should do this according CQRS pattern? Thank you in advance
Hi I'm getting error at line: in .NET 6 Program.cs file builder.Services.AddMediatR(typeof(Program)); Error: CS1503 Argument 2: cannot convert from 'System.Type' to 'System.Action'
Hi Milan thanks for great series of NET tutorials :) I have a question about, what if you have some logic that multiple commands or queries uses in theirs handlers. For example some command update user and some other command have some business logic and update user as well(this is simple example but just think if business logic is more complex than this). How to organize that logic to avoid DRY principle?
I have a question. Can I use DTO object (passing from controller) as a Command parameter? I have dto object in Post Controller (create-new) with a lot of parameters, so creating command with these primitive parameters again then mapping it and then mapping it again in command handler to domain entity is a lot of..mapping and repeating code. I have read in stackoverflow that it is ok solution to encapsulate DTO object in Command (so take it as a argument in constructor) if dto/request has a lot of properties. And then you can mapping it only once in handler - from dto to domain entity.
@@MilanJovanovicTech It is tricky form me. I saw a lot of projects and tutorials and usually they had: 1) Command as a controller action argument that is directly passed to a handler. So Command is a DTO in an API basically. 2) DTO as a controller action argument (like in common api without cqrs) that is mapped manually in a controller body to a command. It can become ugly if we have object with a lot of properties. 3) DTO as a controller action argument that is passed directly to a new command. So Command is some kind of encapsulation to this api object/DTO. It is approach I asked about earlier. What is the best approach in your opinion? Because I cant find one good or a "book" solution and I like your ideas :)
How do you handle error responses? Do you have a generic pipeline that wraps every mediator request with a try-catch and returns a Response.Failure() on error, or would each handler do that inside?
@@MilanJovanovicTech Nice one, but I meant if an error happens inside of the handler that is not caught by validating the requests, i.e. an uncaught exception
@@lukassinkus6162 I see. So I actually recorded that for a video, but it's not ready yet. I create a middleware with a try-catch block, and handle exceptions there. I return a ProblemDetails to the API consumer.
@@MilanJovanovicTech Hi, yes, how did you full structure that persistance project. And, for example if you have to handle multiple databases sources how we can deal that in that project The best approach to handle the persistance
@@MilanJovanovicTech domain models in Core project, commands and queries in Application project, Handlers, DTOs and mapper in Infrastructure. I've seen this approach couple times and I wonder if it's clean from solution perspective.
What's the point of splitting each operation to new command/query handler when you put some logic services to avoid code duplication and that services are now containing logic for multiple purpose? So instead of having one repository, we have one service and multiple handlers
@@MilanJovanovicTech In most use cases you have for example: Order service which is responsible for all the logic related with orders Order repository which is injected into service and is responsible for all save/read operations related with orders. And how I understand cqrs (in case where we have one db and not using cqrs for performance gains) You split all operations from OrderService into seperate Handlers and that makes sens in case of SOLID principle and SOC. But thenm, when you take some code back from those handlers and put back into one common service (what's the point of that?) It's true that you still have command/query separation but also break solid rule with that one service full of logic from that handlers). Also creating OrderRepository and injecting into handlers breaks all above rules, what's the benefit of that repository instead of injecting dbcontext or connection (in case of dapper) and executing queries from handler? I know that main reason for IRepository usage is the case when in future you would like to switch to other db provider but in real life it almost never happen.
Great presentation. Noticed when switching b/w the files, it's not highlighted the appropriate file in the solution explorer. Pls enable that option so that it'll be helpful to see what folders / files you are navigating.
Hello Milan. I'm struggling to implement a many to many relationship while adopting CQRS and MediatR in Clean Architecture. Do you have any video or reference? Including EF core migrations and Edit/Add/Delete commands.
Thanks for the Reply Milan. My implementation of the domain entity models is wrong i think. And i also can't figure out how to update and delete some of the third many to many entity using command handlers.
Hi Milan, When to use Repository Pattern over CQRS in Clean Architecture? because the first time I tried to use CQRS with in a simple app it was a bit slower CQRS with EF core or Dapper for enterprise app?
Hi Milan how do I go about using mediator pattern with factory pattern where the request body can call different handler at runtime based on some property in the JSON payload
I can imagine a solution where you have a branching logic in IPipelineBehavior. But this make sense if this is a common use case in your project. Otherwise, just use if-else in your handler, and decide what to call
@@muhammeteser9571 If you plan to be a Patron long term, I suggest waiting a few days. Since it charges for the whole month upfront, and October is in a few days :)
I hate Unit return type in MediatR. It's so useless for most of the people. I can't see normal reason why author decided to return this instead Task. You need to write your own command bus wrapper to change remove this Task and make it just Task (e.g: public async Task HandleAsync(SomeRequest request, CancellationToken cancellationToken))
@@MilanJovanovicTech Thanks for the fast response. The idea of CQRS is to use different models or storage for your read and your write side, but you never showed that. It is the idea that "Normalized models are great for writing and consistency but slow for reading due to joins", or that "Event sourcing is great for writing but almost impossible for reading". All the handlers and so on are nice to have if you want to have a consistent pattern for your whole application, but not necessary. The interesting part would be in the repository. I could even implement CQRS with the repository and the controllers only.
I'm sorry, but you didn't exactly showed CQRS, you just showed how to use MediatR to a project that already had a repository pattern. The power of CQRS is to be able to separate the Read from the Write so they can use different storage mediums, different read write techniques (e.g using DbContext on the Read, and Repository on the write) to give more flexibility and to decouple them from the same implementation. Juniors or people trying to understand the subject will yet again find another tutorial that mixes CQRS and MediatR together, when they should not.
CQRS isn't about having separate datastores at all, in my opinion. It's about thinking differently about reads and writes by separating them completely. How you go about implementing the actual read/write logic is completely up to you.
@@MilanJovanovicTech You are right and that's why I said it's "to be able to" do the separation. One of my concerns is more towards the title of your tutorial - it emphasize that it's not complicated to do CQRS and the content is about MediatR. CQRS could be as easy as simply having 2 classes, one for read and one for write without even using MediatR. Even so, one of the reason why the pattern could be considered complex is because you have to separate your read and your write, which greatly increase the number of components in your solution. It's something that should be taught to not be used everywhere, only needed by the architecture - otherwise you're just overcomplicating your solution for no benefits.
No-no-no. CQRS MUST be complicated. Plus you need DDD there for sure. Just for you to feel the pain and senseless of being. The more layers beetwen controller and DB you have the better. No matter if you actually reuse them somehow or not. Better if not. Just to charge your customer with more development costs and put release to eternity, because every time you need to go to all the 15 layers spread between 15 projects and make the same changes everywhere, and it takes 15x time-money. And then finally suddely your CQRS ends up with the same database and the same DbContext for reads and for writes which makes everything useless. (There is nothing more eternal than something temporal). Looks great (may be), but it is very annoying. Having worked for 3+ years for a such greenfield solution feel very tired now of words "CQRS" and "DDD". Very verbous, very routine, comes to spaghetti often, you need to be very scrupulous and attentive to not to forget smth smwhr, as the more moving parts the more probability of fail. The joy of simplicity and moving forward fast is definetely not about CQRS.
never return any objects form command or queries. it creates coupled code. command has to be interface. !CommandHandler where TRetType : class handle(T command, [NotNull] TRetType retval) { //retval.SomeDataMember=SomeValue; } now you can chain it, you dont need binders to DataContract. Reverse of controll
@@MilanJovanovicTech it makes it functional. you can path mock objects etc. very usefull in testing. and return type can be errorsClasses or simple bool. Imagine decorated Command that holds 2 or more commands. if you return value or pass non polymorph operand, you have to create binder to project retval1 on retval2.
Get the source code for this video for FREE → the-dotnet-weekly.ck.page/cqrs
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
My question is why "CQRS"?, those four letter should not be together in any meaningful way, why is that stupid name?
@@seanleith5312 check this out: www.milanjovanovic.tech/blog/cqrs-pattern-with-mediatr
Milan, quick tip. Just write a semicolon after the namespace and it will convert them to file scoped. Also ctrl+R & ctrl+G will get rid of all unused using statements.
The more you know. 😁 I appreciate the keyboard shortcut tips!
If you are using VS2022 you can also go into options and set up code cleanup to run on file save, set code cleanup to sort using and cleanup unused and to default the namespace to file scoped. Then you just have to Ctrl+S to apply a whole range of code formatting options that you can configure.
Or you edit the snippet from VisualStudio folder and remove usings, set the class public sealed by default (or internal). Now you don't have to clean the file each time you add a new file ;) it's worth the effort so much
A separate video on how to actually use cancellation tokens would be nice.
Sure thing! That topic seemed to spark a lot of debate so I want to cover it in more detail
This is pretty darn cool. Setup my own project and followed your instructions. I did have to dig through some of the other videos in the series, but I got everything working. I enjoyed your explanation. Your explanation was clear and easy to follow. Thanks for sharing.
Glad it helped!
I totally love these videos, hopefully one day you’ll talk about authentication/authorization!!
Should be soon Jose. Many people asked for that, so I'll prioritize it higher.
Hi Milan,
Great video 😊 I want to ask you which hosting is best for .NET Core 6?
From start it is not clear why you create interface for query and command.
It is great that you learn and describe your material as well, it is good fast method.
I would remove ApiController, additional inheritance, additional object in memory without any gains.
Your own unit of work is anitpattern. EF already implement UoW in dbcontext object. Separate repository is also additional noise. Mediatr handler is independent implementation for single action. You make it depends on the common repository, which has many reasons to change. Also in my experience often repositories does not allow to reuse some logic. In different place the same repository action may require different transaction scopes, which repository does not address any way.
Query/Command interfaces make it more explicit and expressive than using IRequest for representing both concepts.
In the end, it's the same thing underneath, I just prefer having a little bit more expresiveness.
Great explanation! I like your way to show this kind of content! Clean and direct to the point. Keep going!
Thank you very much Rafa!
Thank you Milan, I really enjoy your videos, you have clear explanations, straight to the point, no useless text that would make me move the video player's progressbar :)) keep going man.
Thanks a lot! 😁
Great content!!
Would love to see how to create abstraction for a query when the response consists of properties coming from different aggregates.
Mhm, good idea. I'll see what I can come up with
Great explanation and it's beneficial for understanding command and query concepts.
Glad it was helpful!
Hi! Thanks for your work. I stumbled upon your channel and I'm enjoying. A suggestion: at the beginning you mentioned (3:06) you've already implemented the CQRS (kinda) but it is difficult to find where. I'd love to see since the beginning and it's not easy to find some order in youtube. I've taken a look in the playlist but it's not clear. I'll watch all your videos but it would be great if you have some list (maybe in video description) ordered, it'll be easier for new subscribers.
Thanks a lot!!!
Keep in mind that I recorded this in my first month on TH-cam, so I was pretty bad at giving out value 😅
All this Clean, Super Clean architectural software design approach and this kind of video doesn’t say ‘You don’t need this huge complexity for your small to medium projects, or if you are a beginner’. If you just start your journey to software development road, skip this kind of ‘tutorials’ you will be overwhelmed and your brain will hurt. Just read the official documentation, make small applications, take your time. All this design principles and patterns are just tools that you will need on some, not all, projects. For small and medium projects this kind off approach will over complicate things. Trust me, you can build useful apps that don’t use any of this, keep them simple, stupid 🤪. I don’t say that this are not good at all, in big projects with big teams are a must, otherwise chaos will happen 😇. With time you will learn and figure out what and when you need to use it in order to accomplish your goal. Start small, learn the basics and build up your experience, otherwise you will lose precious time.
Let the viewers decide. I like to think everyone has some common sense in them to be able to critically view some concepts, and figure out if they make sense for them or not.
When giving an advice based on 30 years of experience has become a bad idea? What I said is my opinion and you, like a professional must respect other’s opinions. I didn’t said that everyone need to follow my advice or agree with me. I think that who wants to become a developer has the brain to decide. Please be open for debates, if don’t close the comments for your videos 🤓
Pretty good! The explanation is very clear. Gave you a like!
Much appreciated!
Hey Milan, thanks for this great demonstration of CQRS. Could I maybe suggest a video idea where you show the full variation of the pattern? Including separate APIs, Read/Write models and Read/Write databases? All in combination with Mediator of course within the Clean Architecture & Domain Driven Design. I would be very interested in this. Thanks again for your valuabe content!
Sure, let me make a few hours long course about it 😅
@@MilanJovanovicTech I would 100% watch it but would understand if that's a little too much 😂
I prefer to write my own solution for cqrs instead of making abstraction for mediatr it's not so hard. I prefer stick query handlers close to dbcontext instead of inject repository there. I like your videos, Keep going! :)
What is the added value you get out of implementing it yourself?
Because it is simple to implement and relying on a package for simple implementations can be a problem for long running solutions.
Watch the origin of CQRS there was never need of some library or framework, because it is trivial to implement.
Great Video! I cant get enough of your content. Can you explain a bit more about your Abstraction of Queries? As someone that primarily works with the data and DBA teams, I've seen a lot of different opinions on how queries should be handled to best balance performance, maintainability, and security.
The most performant approach would be create a small service per query handler, which will fetch only the data that is necessary to satisfy that query.
For example, let's say I have a GetMemberByIdQuery and respective handler.
In the video, I'm using a repository.
An alternative would be to inject an interface like this:
IGetMemberByIdSession
Implement this interface in the Persistence project, however we deem fit. We can use EF, we can write a SQL query, etc.
Does this make sense?
@@MilanJovanovicTech Makes sense, thanks for the explanation.
@@MilanJovanovicTech IS that the specification pattern? Or is that something else?
@@pilotboba Something else entirely.
@@MilanJovanovicTech so in this scenario if you have a common behavior that you need in more than one handler, is it make a sence to make the IGet MemberByIdSession implementation inside the Persistence project and call it from both handlers?
I understand all of this, except - whats the point of CQRS from the software point of view, if you have only one storage anyway. It worked without ICommand/IQuery interfaces & handlers just as well. I recently spent some hours debugging our current project, where for some reason data was not saved to dabatase, only to found that I inherited some service from the wrong interface (naming in our project could be better...).
The point is logical splitting of reads/writes.
The additional abstractions are to be more explicit.
As for debugging, I agree on that one.
Hi Milan ,
Thanks for the series .
You can do that on my Patreon: www.patreon.com/milanjovanovic
My first video trying to introduce myself in the CQRS architecture since I need to work with it and got some concepts. Very well-explained, thank you!
Glad it was valuable!
I like my Controllers to be dumb and short, so the requests they receive are the command parameter (or command itself) and the return is an AutoMapper mapped Dto.
Every API endpoint boils down to a one-liner like
return Mapper.Map(commandRequest)
Which can, arguably, also be simplified with a generic type...
Then I use Swagger/OpenAPI to generate the TypeScript models for the frontend to strongly-type glue the two layers together.
One drawback of this approach is modifications towards the frontend; builds will fail if the commands/queries signature changes are not adapted on the UI layer, which is also a benefit as you deny yourself space for error, mistakes are immediately apparent, there's no space for deprecations and the client will only receive a working build with no compile errors.
Disclaimer: I wrote this in the middle of watching the video, seems like we have roughly the same approach, nice work!
Mine is a bit more verbose, but it boils down to the same thing 😁
Thanks Milan!
Don't mention it
Difficult to see the order of your videos and where to start.
I do have a few playlists that follow the topic in a somewhat chronological order
Would be really interesting to see how to separate the storages to the read and write storage and how to sync them so the command will write to the `write` storage and reads will read from optimized `read` storage.
You would write to write storage. Publish an event, and write to read storage. You end up with eventual consistency though.
Separating read model and write model is foremost conceptual. You really need not to have separate implementations or even separate physical data storages-unless there is a requirement to do so. #yagni
What is inside the "Result" class? Would you show us?
Here's an open source alternative: github.com/altmann/FluentResults
@@MilanJovanovicTech Thanks!
Great video Milan, really enjoying these videos and there is always something I am learning. What are your views on vertical slice architecture in comparison to clean architecture?
Hey James :) Haven't used the vertical slice architecture ever, so I don't have any strong opinion on it. I don't mind it in general. But I prefer a layered architecture (like Clean) with stricter separation between concepts.
Thank you for sharing!
You're quite welcome :)
Hi Milan, Thank you for more useful video for CQRS, can you share the links for validation, logging and exception?
Which links?
Great explanation!
Could you please explain, is there any special reason to use records for Queries and commands and their results? While you use class for handlers. I know difference between class and record but I didn't find your idea.
I like that records are immutable
I wonder which benefit you actually see here using MediatR (or messaging in general) over directly calling APIs on some interface? As you use specific command, query and response objects the coupling between the controller and the handler would be similar from my perspective. I would be interested in your arguments for this design choice. thx!
Just a means to an end. It's simple to implement CQRS with it.
@@MilanJovanovicTech It is also simple to implement CQRS without it. But hey, with mediatR we also get to lose IDE navigation on our function calls, yay!
good but CQRS is it CORS or other concept ? and thanks
CQRS = Command Query Responsibility Segregation
CORS = Cross-Origin Resource Sharing
Milan,
Does this pattern always define one handler for each single query or could you have a single interface that define several queries / command and one handler to handle them all?
For example, let's say we have two queries related to the same domain entity. GetOrderById and GetOrderByMember does each will have a respective handler or can we implement one handler for both?
Thanks in advance!
Your videos are great and you explain it really well!
It isn't a problem to handle multiple queries with the same class. I just stick to one query - one handler, by convention
you have to register handler for each query command. They have different logic and should have dif implementation. I do not understand what really you mean
to update logic you change one handler file.
Thanks for your great video... I have a question
Why you didnt use mediatr' sender in your controller for run your commands and queries?
You could inject mediater into your controller and use it
I am injecting ISender which is also MediatR
If you provided a github link to the repo, of this example, that would be super awesome.
You can find something similar on my GitHub. Otherwise, I share the code with my Patreon supporters
I am new on this, you named that folder as "Messaging" because it return a message? Like "Member added with success".
Just a folder holding abstractions for CQRS
Thank you Milan, this rally was a great video! How would the MediatR handle the same command used in two different command handlers ?
You shouldn't share commands. What did you have in mind?
Good video as always. I just I've a question about the queries when they are simple. For example, in your case, you write an entire Command and CommandHandler just to do a simple GetById query. I know this is just an example, but to me, it's an overkill. So if I've do something like this in my code, usually, I inject directly the repository interface into my Controller and I execute the Query. I know this force you to make a dependency from the controller to the repository interface, but is a little cost to pay to don't write a lot of code for a simple GetById Query.
It's just my opinion of course, but I want to know what do you think. As always, thank you for your videos! :)
Indeed, you end up with a lot of files with my approach. This is something I'm used to and I don't mind it
Why did you use as sealed record the Commands? Could you explain about it?
For immutability
Thanks for amazing video please can create example for singlr or hangfire in clean architecture I’m confused where we can put real time communication logic and again thanks very much ❤
Sure thing! I'll add it to my backlog
Thanks 🙏
Do you have a video where you teach approaches from scratch (as in from empty solution/project) ?
This one is more like a part of follow-on series where you're just tweaking a bit inside an already completed full-fledged project.
This series is as close as it gets: th-cam.com/video/fe4iuaoxGbA/w-d-xo.html
Otherwise, there's my PCA course
@@MilanJovanovicTech awesome, thanks Milan. Keep rocking.
Hi Milan, thanks for great videos! Do you use Services along with CQRS handlers for applying reusable logic ?
Only if I see something repeated 2+ times
Hi Milan, great content! How did you implement the Result class in this scenario ??
IsSuccess: bool
IsFailure: bool => !IsSuccess
Error: (string code, string name)
And a few helper static methods for creating a Success/Failure result
Great video Milan! What could you suggest if I want to return 404 Not Found responses instead of 400 Bad Request for cases when an entity not found?
Nothing is stopping you from returning NotFound in the controller
Hi Milan, how do you handle exceptions when using mediatr?
Pipeline behavior, global handler, at the call site...
Thank you Milan,
what the call name of library scan and register service?
Scrutor
@Milan Jovanović, I know this is a pretty old video, but can you please elaborate on how would you retrieve data in your command? Let's say before create a member you have first to retrieve some related data from DB. Will you create a query object inside you command handler? If yes - doesn't this break the idea of CQRS? My question is: sometimes we need to get data in order to write data. Where we should do this according CQRS pattern? Thank you in advance
I would just expose a method on the repository and use it to get the required data.
Hi I'm getting error at line: in .NET 6 Program.cs file
builder.Services.AddMediatR(typeof(Program));
Error:
CS1503 Argument 2: cannot convert from 'System.Type' to 'System.Action'
Maybe using a newer version of MediatR?
@@MilanJovanovicTech yeah that’s a newer version I think 12
good job 👌
Thank you!
Hi Milan thanks for great series of NET tutorials :) I have a question about, what if you have some logic that multiple commands or queries uses in theirs handlers. For example some command update user and some other command have some business logic and update user as well(this is simple example but just think if business logic is more complex than this). How to organize that logic to avoid DRY principle?
Put it in a domain service perhaps? That would be one way to handle it
What the use of cancellation token?
To save server resources
Hi Thanks for this great information. Where is the Result Class coming From?
I implemented it myself. I show it in the Domain Validation video
@@MilanJovanovicTech Thanks Milan! Great work
What do you think about the ErrorOr library for domain/application flow control?
@@richardhaughton9633 It's nice, but I prefer rolling my own
I have a question. Can I use DTO object (passing from controller) as a Command parameter? I have dto object in Post Controller (create-new) with a lot of parameters, so creating command with these primitive parameters again then mapping it and then mapping it again in command handler to domain entity is a lot of..mapping and repeating code. I have read in stackoverflow that it is ok solution to encapsulate DTO object in Command (so take it as a argument in constructor) if dto/request has a lot of properties. And then you can mapping it only once in handler - from dto to domain entity.
Sure. But then you're coupling your API contract and your command. If you're fine with that, go ahead.
@@MilanJovanovicTech It is tricky form me. I saw a lot of projects and tutorials and usually they had:
1) Command as a controller action argument that is directly passed to a handler. So Command is a DTO in an API basically.
2) DTO as a controller action argument (like in common api without cqrs) that is mapped manually in a controller body to a command. It can become ugly if we have object with a lot of properties.
3) DTO as a controller action argument that is passed directly to a new command. So Command is some kind of encapsulation to this api object/DTO. It is approach I asked about earlier.
What is the best approach in your opinion? Because I cant find one good or a "book" solution and I like your ideas :)
Is it a bad idea or bad practice to not use Unit of Work?
I don't think it's a bad idea. It just makes everything a little easier
Hi Milan,
Great video 😊 I want to ask you which hosting is best for .NET Core 6?
There isn't a "best", but Azure is probably easiest to set up
Is there any tutorials with multiple databases for read and write
th-cam.com/video/iKDITShiZy4/w-d-xo.html
How do you handle error responses? Do you have a generic pipeline that wraps every mediator request with a try-catch and returns a Response.Failure() on error, or would each handler do that inside?
Take a look at today's video!
@@MilanJovanovicTech Nice one, but I meant if an error happens inside of the handler that is not caught by validating the requests, i.e. an uncaught exception
@@lukassinkus6162 I see. So I actually recorded that for a video, but it's not ready yet.
I create a middleware with a try-catch block, and handle exceptions there. I return a ProblemDetails to the API consumer.
Milan jovanovic is possible to share videos regarding persistance project?
Talk about that project more?
@@MilanJovanovicTech
Hi, yes, how did you full structure that persistance project. And, for example if you have to handle multiple databases sources how we can deal that in that project
The best approach to handle the persistance
Hi Milan, what do you think about combining Domain models, DTOs and AutoMapper in request handlers in cqrs? Does it break pattern?
In the same physical file? I think it's fine
@@MilanJovanovicTech domain models in Core project, commands and queries in Application project, Handlers, DTOs and mapper in Infrastructure. I've seen this approach couple times and I wonder if it's clean from solution perspective.
Nice work and can you share with what is the theme you are using in visual Studio IDE?
Thanks
VS Dark Theme + R# syntax highlighting
Is it really important to implement unitOfWork or is it up to developer? By the way, I use dbContext directly in my projects.
That's perfectly fine. I also use the DbContext directly on some projects.
@@MilanJovanovicTech thanks for reply
I see you are creating all dependency with scoped lifetime. Is it recommended?
Not all, just the ones that have scoped dependencies
What's the point of splitting each operation to new command/query handler when you put some logic services to avoid code duplication and that services are now containing logic for multiple purpose?
So instead of having one repository, we have one service and multiple handlers
So you want to replace a repository with a service?
@@MilanJovanovicTech In most use cases you have for example:
Order service which is responsible for all the logic related with orders
Order repository which is injected into service and is responsible for all save/read operations related with orders.
And how I understand cqrs (in case where we have one db and not using cqrs for performance gains)
You split all operations from OrderService into seperate Handlers and that makes sens in case of SOLID principle and SOC.
But thenm, when you take some code back from those handlers and put back into one common service (what's the point of that?)
It's true that you still have command/query separation but also break solid rule with that one service full of logic from that handlers).
Also creating OrderRepository and injecting into handlers breaks all above rules, what's the benefit of that repository instead of injecting dbcontext or connection (in case of dapper) and executing queries from handler?
I know that main reason for IRepository usage is the case when in future you would like to switch to other db provider but in real life it almost never happen.
Hello, Do we need to sealed when creating a record? because as far as I know the records are implicitly sealed by default
Are they implicitly sealed? 🤔
@@MilanJovanovicTech My bad, I was confused. Thanks for your great video 😄
Hello Sir, you are a very good instructor. Is there a way to download the source code of Gatherly?
Yes, on Patreon
@@MilanJovanovicTech Ok Sir, thanks...
Good job!
Thanks!
great video ❤ is there link to git repo to explore the code?
Hi Mohamed, the source code is only available for my Patreons. However, you can find something similar here:
github.com/m-jovanovic/event-reminder
@@MilanJovanovicTech how to signup for to be a patreon ? 🙂
@@saqibali7066 You can do it here: www.patreon.com/milanjovanovic
Which theme are you using in VS?
ReSharper dark theme
@@MilanJovanovicTech Thanks can I download this without buying ReSharper?
Great presentation. Noticed when switching b/w the files, it's not highlighted the appropriate file in the solution explorer. Pls enable that option so that it'll be helpful to see what folders / files you are navigating.
I got better in future videos :)
Great Video!
But I think it's CQS and not CQRS (CQS != CQRS) :)
CQS is method level - CQRS is component level
Milan, what VS theme are you using?
ReSharper dark theme
@@MilanJovanovicTech Thanks a ton! Love your videos, keep up the good work!
Hello Milan. I'm struggling to implement a many to many relationship while adopting CQRS and MediatR in Clean Architecture. Do you have any video or reference? Including EF core migrations and Edit/Add/Delete commands.
Which part are you struggling with?
Thanks for the Reply Milan. My implementation of the domain entity models is wrong i think. And i also can't figure out how to update and delete some of the third many to many entity using command handlers.
Hi, what theme u use in vs ?
ReSharper
Hi Milan,
When to use Repository Pattern over CQRS in Clean Architecture? because the first time I tried to use CQRS with in a simple app it was a bit slower
CQRS with EF core or Dapper for enterprise app?
You can use whatever you like. There aren't any rules written in stone.
Your videos are really great to learn. But please talk a little loud :)
Honestly, you are one of the few people complaining. Are you sure the video volume is low? 🤔
Hi Milan how do I go about using mediator pattern with factory pattern where the request body can call different handler at runtime based on some property in the JSON payload
I can imagine a solution where you have a branching logic in IPipelineBehavior. But this make sense if this is a common use case in your project.
Otherwise, just use if-else in your handler, and decide what to call
Hi @@MilanJovanovicTech the if else logic will reside in the controller to call which request command?
Are you in Udemy?? Cause I need to have your lessons!!
No, I'll create my own website for courses very soon. I'll keep you posted :)
Currently not paying I guess there is a technical problem. It say ,We’re sorry, but we were unable to add your card at this time. Please try again.
You're talking about Patreon?
@@MilanJovanovicTech YES
@@muhammeteser9571 If you plan to be a Patron long term, I suggest waiting a few days. Since it charges for the whole month upfront, and October is in a few days :)
This'll save you some money, and give you access to Patreon longee
I hate Unit return type in MediatR. It's so useless for most of the people. I can't see normal reason why author decided to return this instead Task. You need to write your own command bus wrapper to change remove this Task and make it just Task (e.g: public async Task HandleAsync(SomeRequest request, CancellationToken cancellationToken))
I'm sure he had his reasons
@@MilanJovanovicTech used for some kind of synchronization and because method MUST return something otherwise someone will die
Just having a handler is not CQRS. You just created an abstraction over a function call.
Is creating a handler the only thing I did here? What else am I missing? 😅
@@MilanJovanovicTech Thanks for the fast response. The idea of CQRS is to use different models or storage for your read and your write side, but you never showed that. It is the idea that "Normalized models are great for writing and consistency but slow for reading due to joins", or that "Event sourcing is great for writing but almost impossible for reading". All the handlers and so on are nice to have if you want to have a consistent pattern for your whole application, but not necessary. The interesting part would be in the repository. I could even implement CQRS with the repository and the controllers only.
What's the benefit of CQRS?
why it just make things complicated
The benefit is logical separation of reads and writes. Allowing you to model each of them differently.
@@MilanJovanovicTech Thanks for the replying.
but Without CQRS, we can easily to seperate READ and WRITE as well, right?
I'm sorry, but you didn't exactly showed CQRS, you just showed how to use MediatR to a project that already had a repository pattern.
The power of CQRS is to be able to separate the Read from the Write so they can use different storage mediums, different read write techniques (e.g using DbContext on the Read, and Repository on the write) to give more flexibility and to decouple them from the same implementation.
Juniors or people trying to understand the subject will yet again find another tutorial that mixes CQRS and MediatR together, when they should not.
CQRS isn't about having separate datastores at all, in my opinion. It's about thinking differently about reads and writes by separating them completely. How you go about implementing the actual read/write logic is completely up to you.
@@MilanJovanovicTech You are right and that's why I said it's "to be able to" do the separation. One of my concerns is more towards the title of your tutorial - it emphasize that it's not complicated to do CQRS and the content is about MediatR.
CQRS could be as easy as simply having 2 classes, one for read and one for write without even using MediatR.
Even so, one of the reason why the pattern could be considered complex is because you have to separate your read and your write, which greatly increase the number of components in your solution. It's something that should be taught to not be used everywhere, only needed by the architecture - otherwise you're just overcomplicating your solution for no benefits.
lol World of Warcaft
What's so funny?
Classic WotLK, reliving my childhood. 😂
@@MilanJovanovicTech I just finish arena session in wow, open my browser and seen ur video so funny coincident. Also in love with CQRS :)
@@reggyA898 I'm happy that we have similar interests. You'll love this channel for sure 😁
No-no-no. CQRS MUST be complicated. Plus you need DDD there for sure. Just for you to feel the pain and senseless of being. The more layers beetwen controller and DB you have the better. No matter if you actually reuse them somehow or not. Better if not. Just to charge your customer with more development costs and put release to eternity, because every time you need to go to all the 15 layers spread between 15 projects and make the same changes everywhere, and it takes 15x time-money. And then finally suddely your CQRS ends up with the same database and the same DbContext for reads and for writes which makes everything useless. (There is nothing more eternal than something temporal). Looks great (may be), but it is very annoying. Having worked for 3+ years for a such greenfield solution feel very tired now of words "CQRS" and "DDD". Very verbous, very routine, comes to spaghetti often, you need to be very scrupulous and attentive to not to forget smth smwhr, as the more moving parts the more probability of fail. The joy of simplicity and moving forward fast is definetely not about CQRS.
Why though?
A controversial comment... 😂
Don't be that controversial 🤣
I fully disagree.
It's not controversial at all. :)
CSRQ … research that … cdbc related
What? 🤔
MediatR is bad performance
No it's not 😁
@@MilanJovanovicTech th-cam.com/video/baiH3f_TFfY/w-d-xo.html
never return any objects form command or queries. it creates coupled code. command has to be interface. !CommandHandler where TRetType : class
handle(T command, [NotNull] TRetType retval)
{
//retval.SomeDataMember=SomeValue;
}
now you can chain it, you dont need binders to DataContract. Reverse of controll
Never seen this approach used in practice. Doesn't it make way for very strange code?
@@MilanJovanovicTech it makes it functional. you can path mock objects etc. very usefull in testing. and return type can be errorsClasses or simple bool. Imagine decorated Command that holds 2 or more commands. if you return value or pass non polymorph operand, you have to create binder to project retval1 on retval2.
@@MilanJovanovicTech Patterns, Principles, and
Practices of Domain-Driven Design by Scott Millett page 701-704.