CQRS Doesn't Have To Be Complicated | Clean Architecture, .NET 6

  Рет қаралды 102,921

Milan Jovanović

Milan Jovanović

Күн бұрын

Get the source code for this video for FREE → the-dotnet-weekly.ck.page/cqrs
☄️ Master the Modular Monolith Architecture: bit.ly/3SXlzSt
📌 Accelerate your Clean Architecture skills: bit.ly/3PupkOJ
🚀 Support me on Patreon to access the source code: / milanjovanovic
CQRS, which stands for Command Query Responsibility Segregation, is a popular design pattern. In this video, I will show you how to implement CQRS using the MediatR library. We are going to create custom Command and Query abstractions, to make our CQRS implementation more explicit.
Join my weekly .NET newsletter:
www.milanjovanovic.tech
Subscribe for more:
kzbin.info...
Chapters
0:00 What is CQRS?
3:00 CQRS With MediatR
5:27 Explicit Command Abstraction
9:47 Configuring MediatR
11:20 CQRS Command Side in Action
14:59 Explicit Query Abstraction
21:10 CQRS Query Side in Action
23:27 Awesome Outro

Пікірлер: 217
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Master the Clean Architecture: bit.ly/3PupkOJ
@seanleith5312
@seanleith5312 8 ай бұрын
My question is why "CQRS"?, those four letter should not be together in any meaningful way, why is that stupid name?
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
@@seanleith5312 check this out: www.milanjovanovic.tech/blog/cqrs-pattern-with-mediatr
@danilodjokic5303
@danilodjokic5303 Жыл бұрын
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.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
The more you know. 😁 I appreciate the keyboard shortcut tips!
@AlmightySimian
@AlmightySimian Жыл бұрын
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.
@Nk54fr
@Nk54fr 6 ай бұрын
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
@SamFugarino
@SamFugarino Күн бұрын
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.
@MilanJovanovicTech
@MilanJovanovicTech 21 сағат бұрын
Glad it helped!
@rafapioli75
@rafapioli75 Жыл бұрын
Great explanation! I like your way to show this kind of content! Clean and direct to the point. Keep going!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Thank you very much Rafa!
@calinmarian2553
@calinmarian2553 Жыл бұрын
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.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Thanks a lot! 😁
@majormartintibor
@majormartintibor Жыл бұрын
A separate video on how to actually use cancellation tokens would be nice.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Sure thing! That topic seemed to spark a lot of debate so I want to cover it in more detail
@joshem32
@joshem32 Жыл бұрын
I totally love these videos, hopefully one day you’ll talk about authentication/authorization!!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Should be soon Jose. Many people asked for that, so I'll prioritize it higher.
@alvedingasal6782
@alvedingasal6782 Жыл бұрын
Hi Milan, Great video 😊 I want to ask you which hosting is best for .NET Core 6?
@saqibali7066
@saqibali7066 Жыл бұрын
Hi Milan , Thanks for the series .
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You can do that on my Patreon: www.patreon.com/milanjovanovic
@lexdxw1989
@lexdxw1989 Жыл бұрын
Pretty good! The explanation is very clear. Gave you a like!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Much appreciated!
@javedahmad9166
@javedahmad9166 Жыл бұрын
Great content!! Would love to see how to create abstraction for a query when the response consists of properties coming from different aggregates.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Mhm, good idea. I'll see what I can come up with
@saulolima6874
@saulolima6874 Жыл бұрын
Thanks Milan!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Don't mention it
@avecesar
@avecesar Жыл бұрын
Thank you for sharing!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You're quite welcome :)
@JoseSilva-ci5mz
@JoseSilva-ci5mz 10 ай бұрын
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!
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
Glad it was valuable!
@IldarIsm
@IldarIsm Жыл бұрын
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.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
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.
@silvertek
@silvertek Жыл бұрын
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.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
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?
@silvertek
@silvertek Жыл бұрын
@@MilanJovanovicTech Makes sense, thanks for the explanation.
@pilotboba
@pilotboba Жыл бұрын
@@MilanJovanovicTech IS that the specification pattern? Or is that something else?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
@@pilotboba Something else entirely.
@ahmadalsader1047
@ahmadalsader1047 Жыл бұрын
@@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?
@jamesevans6438
@jamesevans6438 Жыл бұрын
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?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
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.
@jmiltons
@jmiltons Жыл бұрын
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!!!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Keep in mind that I recorded this in my first month on KZbin, so I was pretty bad at giving out value 😅
@Sentrify
@Sentrify 9 ай бұрын
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!
@MilanJovanovicTech
@MilanJovanovicTech 9 ай бұрын
Sure, let me make a few hours long course about it 😅
@Sentrify
@Sentrify 9 ай бұрын
@@MilanJovanovicTech I would 100% watch it but would understand if that's a little too much 😂
11 ай бұрын
good job 👌
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Thank you!
@Dragonite594
@Dragonite594 Жыл бұрын
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! :)
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
What is the added value you get out of implementing it yourself?
@RealDieselMeister
@RealDieselMeister Жыл бұрын
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.
@SPribyt
@SPribyt 4 ай бұрын
Good job!
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
Thanks!
@sikelelankohla1499
@sikelelankohla1499 Жыл бұрын
Thank you Milan, this rally was a great video! How would the MediatR handle the same command used in two different command handlers ?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You shouldn't share commands. What did you have in mind?
@10199able
@10199able Жыл бұрын
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...).
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
The point is logical splitting of reads/writes. The additional abstractions are to be more explicit. As for debugging, I agree on that one.
@goorn4489
@goorn4489 Жыл бұрын
Hi Milan, thanks for great videos! Do you use Services along with CQRS handlers for applying reusable logic ?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Only if I see something repeated 2+ times
@Ruslan.Galiev
@Ruslan.Galiev Жыл бұрын
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?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Nothing is stopping you from returning NotFound in the controller
@yaroslavsmoliak5725
@yaroslavsmoliak5725 Жыл бұрын
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.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You would write to write storage. Publish an event, and write to read storage. You end up with eventual consistency though.
@krccmsitp2884
@krccmsitp2884 Жыл бұрын
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
@mptechie
@mptechie Жыл бұрын
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.
@mptechie
@mptechie Жыл бұрын
Disclaimer: I wrote this in the middle of watching the video, seems like we have roughly the same approach, nice work!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Mine is a bit more verbose, but it boils down to the same thing 😁
@AdamWandoch
@AdamWandoch 11 ай бұрын
Hi Milan, great content! How did you implement the Result class in this scenario ??
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
IsSuccess: bool IsFailure: bool => !IsSuccess Error: (string code, string name) And a few helper static methods for creating a Success/Failure result
@AboutCleanCode
@AboutCleanCode Жыл бұрын
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
@MilanJovanovicTech Жыл бұрын
Just a means to an end. It's simple to implement CQRS with it.
@andrewshirley9240
@andrewshirley9240 Жыл бұрын
@@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!
@tomislavpapic3158
@tomislavpapic3158 Жыл бұрын
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?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Put it in a domain service perhaps? That would be one way to handle it
@newenglish4109
@newenglish4109 11 ай бұрын
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
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
I am injecting ISender which is also MediatR
@adisilagy
@adisilagy Жыл бұрын
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!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
It isn't a problem to handle multiple queries with the same class. I just stick to one query - one handler, by convention
@IldarIsm
@IldarIsm Жыл бұрын
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.
@evilTano
@evilTano Жыл бұрын
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! :)
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
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
@AbdllahBinHatheemAliGeeSuth
@AbdllahBinHatheemAliGeeSuth Жыл бұрын
Thank you Milan, what the call name of library scan and register service?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Scrutor
@alvedingasal6782
@alvedingasal6782 Жыл бұрын
Hi Milan, Great video 😊 I want to ask you which hosting is best for .NET Core 6?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
There isn't a "best", but Azure is probably easiest to set up
@aliakseiavechkin2794
@aliakseiavechkin2794 8 ай бұрын
@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
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
I would just expose a method on the repository and use it to get the required data.
@PK-wb6cs
@PK-wb6cs Жыл бұрын
Hi Milan, what do you think about combining Domain models, DTOs and AutoMapper in request handlers in cqrs? Does it break pattern?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
In the same physical file? I think it's fine
@PK-wb6cs
@PK-wb6cs Жыл бұрын
@@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.
@vagnerwentz1189
@vagnerwentz1189 Жыл бұрын
Why did you use as sealed record the Commands? Could you explain about it?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
For immutability
@shunz5677
@shunz5677 Жыл бұрын
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
@MilanJovanovicTech Жыл бұрын
Sure. But then you're coupling your API contract and your command. If you're fine with that, go ahead.
@shunz5677
@shunz5677 Жыл бұрын
@@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 :)
@eliesamyoun1006
@eliesamyoun1006 4 ай бұрын
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.
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
Which part are you struggling with?
@eliesamyoun1006
@eliesamyoun1006 4 ай бұрын
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.
@lukassinkus6162
@lukassinkus6162 Жыл бұрын
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
@MilanJovanovicTech Жыл бұрын
Take a look at today's video!
@lukassinkus6162
@lukassinkus6162 Жыл бұрын
@@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
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
@@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.
@TheTeladras
@TheTeladras Жыл бұрын
If you provided a github link to the repo, of this example, that would be super awesome.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You can find something similar on my GitHub. Otherwise, I share the code with my Patreon supporters
@relaxlifeentertainment1282
@relaxlifeentertainment1282 8 ай бұрын
Nice work and can you share with what is the theme you are using in visual Studio IDE? Thanks
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
VS Dark Theme + R# syntax highlighting
@marcelotieghi936
@marcelotieghi936 7 ай бұрын
I am new on this, you named that folder as "Messaging" because it return a message? Like "Member added with success".
@MilanJovanovicTech
@MilanJovanovicTech 7 ай бұрын
Just a folder holding abstractions for CQRS
@ChristianAltamiranoAyala
@ChristianAltamiranoAyala 4 ай бұрын
Hi Milan, how do you handle exceptions when using mediatr?
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
Pipeline behavior, global handler, at the call site...
@pieceofcode_
@pieceofcode_ Жыл бұрын
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'
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Maybe using a newer version of MediatR?
@pieceofcode_
@pieceofcode_ Жыл бұрын
@@MilanJovanovicTech yeah that’s a newer version I think 12
@amonra655
@amonra655 Жыл бұрын
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 ❤
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Sure thing! I'll add it to my backlog
@amonra655
@amonra655 Жыл бұрын
Thanks 🙏
@nicathidayetzade1482
@nicathidayetzade1482 Жыл бұрын
Is it really important to implement unitOfWork or is it up to developer? By the way, I use dbContext directly in my projects.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
That's perfectly fine. I also use the DbContext directly on some projects.
@nicathidayetzade1482
@nicathidayetzade1482 Жыл бұрын
@@MilanJovanovicTech thanks for reply
@TienHoang-ui4zj
@TienHoang-ui4zj 2 ай бұрын
Hello, Do we need to sealed when creating a record? because as far as I know the records are implicitly sealed by default
@MilanJovanovicTech
@MilanJovanovicTech 2 ай бұрын
Are they implicitly sealed? 🤔
@TienHoang-ui4zj
@TienHoang-ui4zj 2 ай бұрын
@@MilanJovanovicTech My bad, I was confused. Thanks for your great video 😄
@gligom
@gligom Жыл бұрын
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.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
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.
@gligom
@gligom Жыл бұрын
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 🤓
@aktierportfolio1365
@aktierportfolio1365 Жыл бұрын
Difficult to see the order of your videos and where to start.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I do have a few playlists that follow the topic in a somewhat chronological order
@nicolaiblas
@nicolaiblas Жыл бұрын
Milan, what VS theme are you using?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
ReSharper dark theme
@nicolaiblas
@nicolaiblas Жыл бұрын
@@MilanJovanovicTech Thanks a ton! Love your videos, keep up the good work!
@winstochurgle9133
@winstochurgle9133 Жыл бұрын
What is inside the "Result" class? Would you show us?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Here's an open source alternative: github.com/altmann/FluentResults
@winstochurgle9133
@winstochurgle9133 Жыл бұрын
@@MilanJovanovicTech Thanks!
@ManuraSiriwardena
@ManuraSiriwardena 3 ай бұрын
Is there any tutorials with multiple databases for read and write
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
kzbin.info/www/bejne/n3yneoeJnc6Nr5Y
@Shanks-at-Work
@Shanks-at-Work 4 ай бұрын
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.
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
This series is as close as it gets: kzbin.info/www/bejne/nJaXmqiXpN16mKM Otherwise, there's my PCA course
@Shanks-at-Work
@Shanks-at-Work 4 ай бұрын
@@MilanJovanovicTech awesome, thanks Milan. Keep rocking.
@richardhaughton9633
@richardhaughton9633 Жыл бұрын
Hi Thanks for this great information. Where is the Result Class coming From?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I implemented it myself. I show it in the Domain Validation video
@richardhaughton9633
@richardhaughton9633 Жыл бұрын
@@MilanJovanovicTech Thanks Milan! Great work
@richardhaughton9633
@richardhaughton9633 Жыл бұрын
What do you think about the ErrorOr library for domain/application flow control?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
@@richardhaughton9633 It's nice, but I prefer rolling my own
@juanitotomasjr.389
@juanitotomasjr.389 Жыл бұрын
Hello Sir, you are a very good instructor. Is there a way to download the source code of Gatherly?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Yes, on Patreon
@juanitotomasjr.389
@juanitotomasjr.389 Жыл бұрын
@@MilanJovanovicTech Ok Sir, thanks...
@MDM666666
@MDM666666 Жыл бұрын
Which theme are you using in VS?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
ReSharper dark theme
@MDM666666
@MDM666666 Жыл бұрын
@@MilanJovanovicTech Thanks can I download this without buying ReSharper?
@Tamer_Ali
@Tamer_Ali Жыл бұрын
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?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You can use whatever you like. There aren't any rules written in stone.
@anton_roos
@anton_roos Жыл бұрын
Is it a bad idea or bad practice to not use Unit of Work?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I don't think it's a bad idea. It just makes everything a little easier
@Nazaro4ka
@Nazaro4ka 8 ай бұрын
What the use of cancellation token?
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
To save server resources
@fabiosantos1679
@fabiosantos1679 Жыл бұрын
Milan jovanovic is possible to share videos regarding persistance project?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Talk about that project more?
@fabiosantos1679
@fabiosantos1679 Жыл бұрын
@@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
@dvsys751
@dvsys751 3 ай бұрын
Hi, what theme u use in vs ?
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
ReSharper
@achrafaffes1588
@achrafaffes1588 Жыл бұрын
good but CQRS is it CORS or other concept ? and thanks
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
CQRS = Command Query Responsibility Segregation CORS = Cross-Origin Resource Sharing
@simbatwiga9631
@simbatwiga9631 Жыл бұрын
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
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
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
@simbatwiga9631
@simbatwiga9631 Жыл бұрын
Hi @@MilanJovanovicTech the if else logic will reside in the controller to call which request command?
@mohameddabbour6961
@mohameddabbour6961 Жыл бұрын
great video ❤ is there link to git repo to explore the code?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Hi Mohamed, the source code is only available for my Patreons. However, you can find something similar here: github.com/m-jovanovic/event-reminder
@saqibali7066
@saqibali7066 Жыл бұрын
@@MilanJovanovicTech how to signup for to be a patreon ? 🙂
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
@@saqibali7066 You can do it here: www.patreon.com/milanjovanovic
@TheJabukasiga
@TheJabukasiga Ай бұрын
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
@MilanJovanovicTech Ай бұрын
So you want to replace a repository with a service?
@TheJabukasiga
@TheJabukasiga Ай бұрын
​@@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.
@user-cr8ez3ig8q
@user-cr8ez3ig8q 4 ай бұрын
I see you are creating all dependency with scoped lifetime. Is it recommended?
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
Not all, just the ones that have scoped dependencies
@faridmurshudov5796
@faridmurshudov5796 Жыл бұрын
Your videos are really great to learn. But please talk a little loud :)
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Honestly, you are one of the few people complaining. Are you sure the video volume is low? 🤔
@surendrakumar-mk7sr
@surendrakumar-mk7sr 9 ай бұрын
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.
@MilanJovanovicTech
@MilanJovanovicTech 9 ай бұрын
I got better in future videos :)
@desaihiren2009
@desaihiren2009 6 ай бұрын
Great Video! But I think it's CQS and not CQRS (CQS != CQRS) :)
@MilanJovanovicTech
@MilanJovanovicTech 6 ай бұрын
CQS is method level - CQRS is component level
@anthony2584
@anthony2584 Жыл бұрын
Are you in Udemy?? Cause I need to have your lessons!!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
No, I'll create my own website for courses very soon. I'll keep you posted :)
@muhammeteser9571
@muhammeteser9571 Жыл бұрын
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.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You're talking about Patreon?
@muhammeteser9571
@muhammeteser9571 Жыл бұрын
@@MilanJovanovicTech YES
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
@@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 :)
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
This'll save you some money, and give you access to Patreon longee
@reggyA898
@reggyA898 Жыл бұрын
lol World of Warcaft
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
What's so funny? Classic WotLK, reliving my childhood. 😂
@reggyA898
@reggyA898 Жыл бұрын
@@MilanJovanovicTech I just finish arena session in wow, open my browser and seen ur video so funny coincident. Also in love with CQRS :)
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
@@reggyA898 I'm happy that we have similar interests. You'll love this channel for sure 😁
@malignate4sd
@malignate4sd Жыл бұрын
Just having a handler is not CQRS. You just created an abstraction over a function call.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Is creating a handler the only thing I did here? What else am I missing? 😅
@malignate4sd
@malignate4sd Жыл бұрын
​@@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.
@zikkrype
@zikkrype Жыл бұрын
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
@MilanJovanovicTech Жыл бұрын
I'm sure he had his reasons
@zikkrype
@zikkrype Жыл бұрын
@@MilanJovanovicTech used for some kind of synchronization and because method MUST return something otherwise someone will die
@ZhangJay
@ZhangJay Жыл бұрын
What's the benefit of CQRS? why it just make things complicated
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
The benefit is logical separation of reads and writes. Allowing you to model each of them differently.
@ZhangJay
@ZhangJay Жыл бұрын
@@MilanJovanovicTech Thanks for the replying. but Without CQRS, we can easily to seperate READ and WRITE as well, right?
@NiamaImia
@NiamaImia Жыл бұрын
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.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Why though?
@ed-ou812
@ed-ou812 Жыл бұрын
CSRQ … research that … cdbc related
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
What? 🤔
@fullstackdotnet
@fullstackdotnet Жыл бұрын
A controversial comment... 😂
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Don't be that controversial 🤣
@pilotboba
@pilotboba Жыл бұрын
I fully disagree. It's not controversial at all. :)
@finickyflame
@finickyflame Жыл бұрын
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.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
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.
@finickyflame
@finickyflame Жыл бұрын
@@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.
@deedev7279
@deedev7279 Жыл бұрын
MediatR is bad performance
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
No it's not 😁
@deedev7279
@deedev7279 Жыл бұрын
@@MilanJovanovicTech kzbin.info/www/bejne/mJLMeWaclLl5nLs
@alexeybeloushko7240
@alexeybeloushko7240 20 күн бұрын
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
@MilanJovanovicTech 20 күн бұрын
Never seen this approach used in practice. Doesn't it make way for very strange code?
@alexeybeloushko7240
@alexeybeloushko7240 20 күн бұрын
@@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.
@alexeybeloushko7240
@alexeybeloushko7240 20 күн бұрын
@@MilanJovanovicTech Patterns, Principles, and Practices of Domain-Driven Design by Scott Millett page 701-704.
How to Implement the CQRS Pattern in Clean Architecture (from scratch)
17:36
How slow is MediatR really?
15:51
Nick Chapsas
Рет қаралды 60 М.
LOVE LETTER - POPPY PLAYTIME CHAPTER 3 | GH'S ANIMATION
00:15
I CAN’T BELIEVE I LOST 😱
00:46
Topper Guild
Рет қаралды 98 МЛН
HOW DID HE WIN? 😱
00:33
Topper Guild
Рет қаралды 30 МЛН
CQRS & MediatR in a .NET 8 Web API 🚀
22:00
Patrick God
Рет қаралды 4,5 М.
.NET 7  💥  - Intro to CQRS and MediatR with ASP.NET Core Web Api
1:06:48
Clean ASP.NET Core API using MediatR and CQRS | Setup
22:39
Nick Chapsas
Рет қаралды 319 М.
Greg Young - A Decade of DDD, CQRS, Event Sourcing
48:04
Domain-Driven Design Europe
Рет қаралды 181 М.
A Complete .NET Developer's Guide to Span with Stephen Toub
1:02:48
Hisense Official Flagship Store Hisense is the champion What is going on?
0:11
Special Effects Funny 44
Рет қаралды 2,7 МЛН
Blue Mobile 📲 Best For Long Audio Call 📞 💙
0:41
Tech Official
Рет қаралды 1 МЛН
Tag her 🤭💞 #miniphone #smartphone #iphone #samsung #fyp
0:11
Pockify™
Рет қаралды 19 МЛН
КРУТОЙ ТЕЛЕФОН
0:16
KINO KAIF
Рет қаралды 2,3 МЛН
Simple maintenance. #leddisplay #ledscreen #ledwall #ledmodule #ledinstallation
0:19
LED Screen Factory-EagerLED
Рет қаралды 23 МЛН