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

Поділитися
Вставка
  • Опубліковано 20 вер 2024

КОМЕНТАРІ • 230

  • @MilanJovanovicTech
    @MilanJovanovicTech  2 роки тому +11

    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

    • @seanleith5312
      @seanleith5312 11 місяців тому

      My question is why "CQRS"?, those four letter should not be together in any meaningful way, why is that stupid name?

    • @MilanJovanovicTech
      @MilanJovanovicTech  11 місяців тому

      @@seanleith5312 check this out: www.milanjovanovic.tech/blog/cqrs-pattern-with-mediatr

  • @danilodjokic5303
    @danilodjokic5303 2 роки тому +57

    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  2 роки тому +11

      The more you know. 😁 I appreciate the keyboard shortcut tips!

    • @AlmightySimian
      @AlmightySimian 2 роки тому +7

      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 8 місяців тому

      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

  • @majormartintibor
    @majormartintibor 2 роки тому +19

    A separate video on how to actually use cancellation tokens would be nice.

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому +8

      Sure thing! That topic seemed to spark a lot of debate so I want to cover it in more detail

  • @joshem32
    @joshem32 2 роки тому +8

    I totally love these videos, hopefully one day you’ll talk about authentication/authorization!!

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому +11

      Should be soon Jose. Many people asked for that, so I'll prioritize it higher.

    • @alvedingasal6782
      @alvedingasal6782 2 роки тому

      Hi Milan,
      Great video 😊 I want to ask you which hosting is best for .NET Core 6?

  • @SamFugarino
    @SamFugarino 2 місяці тому +1

    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.

  • @rafapioli75
    @rafapioli75 2 роки тому +9

    Great explanation! I like your way to show this kind of content! Clean and direct to the point. Keep going!

  • @calinmarian2553
    @calinmarian2553 Рік тому +3

    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.

  • @lexdxw1989
    @lexdxw1989 Рік тому +3

    Pretty good! The explanation is very clear. Gave you a like!

  • @IldarIsm
    @IldarIsm 2 роки тому +4

    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  2 роки тому +5

      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.

  • @jmiltons
    @jmiltons Рік тому +2

    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 UA-cam, so I was pretty bad at giving out value 😅

  • @Sentrify
    @Sentrify Рік тому +2

    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  Рік тому +2

      Sure, let me make a few hours long course about it 😅

    • @Sentrify
      @Sentrify Рік тому

      @@MilanJovanovicTech I would 100% watch it but would understand if that's a little too much 😂

  • @10199able
    @10199able 2 роки тому +4

    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  2 роки тому +3

      The point is logical splitting of reads/writes.
      The additional abstractions are to be more explicit.
      As for debugging, I agree on that one.

  • @saqibali7066
    @saqibali7066 2 роки тому +1

    Hi Milan ,
    Thanks for the series .

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому

      You can do that on my Patreon: www.patreon.com/milanjovanovic

  • @javedahmad9166
    @javedahmad9166 Рік тому +2

    Great content!!
    Would love to see how to create abstraction for a query when the response consists of properties coming from different aggregates.

  • @silvertek
    @silvertek 2 роки тому +2

    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  2 роки тому +1

      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 2 роки тому +1

      @@MilanJovanovicTech Makes sense, thanks for the explanation.

    • @pilotboba
      @pilotboba 2 роки тому

      @@MilanJovanovicTech IS that the specification pattern? Or is that something else?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому

      @@pilotboba Something else entirely.

    • @ahmadalsader1047
      @ahmadalsader1047 2 роки тому +1

      @@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?

  • @jokersilva09
    @jokersilva09 Рік тому +1

    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!

  • @RahulLohar-lz9wu
    @RahulLohar-lz9wu 2 місяці тому

    Great explanation and it's beneficial for understanding command and query concepts.

  • @gligom
    @gligom Рік тому +2

    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 Рік тому +1

      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 🤓

  • @mptechie
    @mptechie Рік тому +1

    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 😁

  • @Dragonite594
    @Dragonite594 2 роки тому +3

    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  2 роки тому +1

      What is the added value you get out of implementing it yourself?

    • @RealDieselMeister
      @RealDieselMeister 2 роки тому +4

      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.

  • @winstochurgle9133
    @winstochurgle9133 Рік тому +2

    What is inside the "Result" class? Would you show us?

  • @aktierportfolio1365
    @aktierportfolio1365 Рік тому +3

    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

  • @avecesar
    @avecesar 2 роки тому +1

    Thank you for sharing!

  • @saulolima6874
    @saulolima6874 Рік тому +1

    Thanks Milan!

  • @AboutCleanCode
    @AboutCleanCode 2 роки тому +2

    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  2 роки тому

      Just a means to an end. It's simple to implement CQRS with it.

    • @andrewshirley9240
      @andrewshirley9240 2 роки тому +4

      @@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!

  • @achrafaffes1588
    @achrafaffes1588 Рік тому +2

    good but CQRS is it CORS or other concept ? and thanks

    • @MilanJovanovicTech
      @MilanJovanovicTech  Рік тому +1

      CQRS = Command Query Responsibility Segregation
      CORS = Cross-Origin Resource Sharing

  • @gunnbr
    @gunnbr 15 днів тому

    Thanks for the great videos on CQRS, Milan. Unfortunately, the 2 videos of yours I've watched so far don't cover the one case my team is debating. Do you recommend using the Command objects directly as the input for the endpoints or do you use DTO objects and then have the handler convert from DTO to CQRS Command objects?

    • @MilanJovanovicTech
      @MilanJovanovicTech  15 днів тому

      I discussed that in some of my videos. In general, I prefer having a separate object for API inputs. Decoupling the public and the internal API.

  • @trnqx626
    @trnqx626 11 днів тому

    I am your new fan of your videos, I almost watched all of it. I am interested with the clean architecture. I am planning to apply this with my future project I hope where's a way I can contact you if I have questions :)

  • @Shanks-at-Work
    @Shanks-at-Work 7 місяців тому

    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  7 місяців тому +1

      This series is as close as it gets: ua-cam.com/video/fe4iuaoxGbA/v-deo.html
      Otherwise, there's my PCA course

    • @Shanks-at-Work
      @Shanks-at-Work 7 місяців тому

      @@MilanJovanovicTech awesome, thanks Milan. Keep rocking.

  • @adisilagy
    @adisilagy 2 роки тому +2

    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  2 роки тому +1

      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 2 роки тому

      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.

  • @mohammadalisehhat2027
    @mohammadalisehhat2027 Місяць тому

    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.

  • @yaroslavsmoliak5725
    @yaroslavsmoliak5725 2 роки тому +1

    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  2 роки тому

      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

  • @jamesevans6438
    @jamesevans6438 2 роки тому +1

    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  2 роки тому

      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.

  • @newenglish4109
    @newenglish4109 Рік тому +1

    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

  • @ravineela367
    @ravineela367 Місяць тому

    Hi Milan, Thank you for more useful video for CQRS, can you share the links for validation, logging and exception?

  • @marcelotieghi936
    @marcelotieghi936 9 місяців тому +1

    I am new on this, you named that folder as "Messaging" because it return a message? Like "Member added with success".

  • @TheTeladras
    @TheTeladras 2 роки тому +2

    If you provided a github link to the repo, of this example, that would be super awesome.

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому

      You can find something similar on my GitHub. Otherwise, I share the code with my Patreon supporters

  • @evilTano
    @evilTano 2 роки тому +2

    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  2 роки тому +1

      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

  • @sikelelankohla1499
    @sikelelankohla1499 Рік тому +1

    Thank you Milan, this rally was a great video! How would the MediatR handle the same command used in two different command handlers ?

  • @goorn4489
    @goorn4489 Рік тому +1

    Hi Milan, thanks for great videos! Do you use Services along with CQRS handlers for applying reusable logic ?

  • @pieceofcode_
    @pieceofcode_ Рік тому +1

    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

  • @AdamWandoch
    @AdamWandoch Рік тому +1

    Hi Milan, great content! How did you implement the Result class in this scenario ??

    • @MilanJovanovicTech
      @MilanJovanovicTech  Рік тому +1

      IsSuccess: bool
      IsFailure: bool => !IsSuccess
      Error: (string code, string name)
      And a few helper static methods for creating a Success/Failure result

  • @richardhaughton9633
    @richardhaughton9633 2 роки тому +2

    Hi Thanks for this great information. Where is the Result Class coming From?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому

      I implemented it myself. I show it in the Domain Validation video

    • @richardhaughton9633
      @richardhaughton9633 2 роки тому

      @@MilanJovanovicTech Thanks Milan! Great work

    • @richardhaughton9633
      @richardhaughton9633 2 роки тому

      What do you think about the ErrorOr library for domain/application flow control?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому

      @@richardhaughton9633 It's nice, but I prefer rolling my own

  • @aliakseiavechkin2794
    @aliakseiavechkin2794 11 місяців тому

    @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  11 місяців тому +1

      I would just expose a method on the repository and use it to get the required data.

  • @Ruslan.Galiev
    @Ruslan.Galiev Рік тому +1

    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

  • @tomislavpapic3158
    @tomislavpapic3158 Рік тому +1

    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

  • @CarlosMay-t8h
    @CarlosMay-t8h 14 днів тому

    Fascinating!

  • @TheJabukasiga
    @TheJabukasiga 4 місяці тому

    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  4 місяці тому

      So you want to replace a repository with a service?

    • @TheJabukasiga
      @TheJabukasiga 4 місяці тому

      ​@@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.

  •  Рік тому +1

    good job 👌

  • @vagnerwentz1189
    @vagnerwentz1189 2 роки тому +1

    Why did you use as sealed record the Commands? Could you explain about it?

  • @AbdllahBinHatheemAliGeeSuth
    @AbdllahBinHatheemAliGeeSuth 2 роки тому +1

    Thank you Milan,
    what the call name of library scan and register service?

  • @fabiosantos1679
    @fabiosantos1679 Рік тому +1

    Milan jovanovic is possible to share videos regarding persistance project?

    • @MilanJovanovicTech
      @MilanJovanovicTech  Рік тому +1

      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

  • @ChristianAltamiranoAyala
    @ChristianAltamiranoAyala 7 місяців тому +1

    Hi Milan, how do you handle exceptions when using mediatr?

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      Pipeline behavior, global handler, at the call site...

  • @amonra655
    @amonra655 2 роки тому +1

    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 ❤

  • @alvedingasal6782
    @alvedingasal6782 2 роки тому +1

    Hi Milan,
    Great video 😊 I want to ask you which hosting is best for .NET Core 6?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому

      There isn't a "best", but Azure is probably easiest to set up

  • @juanitotomasjr.389
    @juanitotomasjr.389 Рік тому +1

    Hello Sir, you are a very good instructor. Is there a way to download the source code of Gatherly?

  • @NagarajPuthiyavan-j5m
    @NagarajPuthiyavan-j5m 6 місяців тому

    I see you are creating all dependency with scoped lifetime. Is it recommended?

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 місяців тому

      Not all, just the ones that have scoped dependencies

  • @PK-wb6cs
    @PK-wb6cs Рік тому +1

    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.

  • @anton_roos
    @anton_roos 2 роки тому +1

    Is it a bad idea or bad practice to not use Unit of Work?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому

      I don't think it's a bad idea. It just makes everything a little easier

  • @nicathidayetzade1482
    @nicathidayetzade1482 Рік тому +1

    Is it really important to implement unitOfWork or is it up to developer? By the way, I use dbContext directly in my projects.

  • @desaihiren2009
    @desaihiren2009 9 місяців тому +1

    Great Video!
    But I think it's CQS and not CQRS (CQS != CQRS) :)

  • @lukassinkus6162
    @lukassinkus6162 2 роки тому +1

    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  2 роки тому

      Take a look at today's video!

    • @lukassinkus6162
      @lukassinkus6162 2 роки тому +1

      @@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  2 роки тому

      @@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.

  • @relaxlifeentertainment1282
    @relaxlifeentertainment1282 11 місяців тому

    Nice work and can you share with what is the theme you are using in visual Studio IDE?
    Thanks

  • @shunz5677
    @shunz5677 Рік тому +1

    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  Рік тому +1

      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 :)

  • @surendrakumar-mk7sr
    @surendrakumar-mk7sr 11 місяців тому

    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.

  • @TienHoang-ui4zj
    @TienHoang-ui4zj 4 місяці тому

    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  4 місяці тому

      Are they implicitly sealed? 🤔

    • @TienHoang-ui4zj
      @TienHoang-ui4zj 4 місяці тому

      @@MilanJovanovicTech My bad, I was confused. Thanks for your great video 😄

  • @anthony2584
    @anthony2584 Рік тому +1

    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 :)

  • @ManuraSiriwardena
    @ManuraSiriwardena 5 місяців тому

    Is there any tutorials with multiple databases for read and write

  • @Nazaro4ka
    @Nazaro4ka 11 місяців тому +1

    What the use of cancellation token?

  • @nicolaiblas
    @nicolaiblas 2 роки тому +1

    Milan, what VS theme are you using?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому

      ReSharper dark theme

    • @nicolaiblas
      @nicolaiblas 2 роки тому

      @@MilanJovanovicTech Thanks a ton! Love your videos, keep up the good work!

  • @mohameddabbour6961
    @mohameddabbour6961 2 роки тому +2

    great video ❤ is there link to git repo to explore the code?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому

      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 2 роки тому

      @@MilanJovanovicTech how to signup for to be a patreon ? 🙂

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому

      @@saqibali7066 You can do it here: www.patreon.com/milanjovanovic

  • @SPribyt
    @SPribyt 6 місяців тому

    Good job!

  • @eliesamyoun1006
    @eliesamyoun1006 7 місяців тому

    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  7 місяців тому

      Which part are you struggling with?

    • @eliesamyoun1006
      @eliesamyoun1006 7 місяців тому

      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.

  • @MDM666666
    @MDM666666 Рік тому +1

    Which theme are you using in VS?

    • @MilanJovanovicTech
      @MilanJovanovicTech  Рік тому

      ReSharper dark theme

    • @MDM666666
      @MDM666666 Рік тому

      @@MilanJovanovicTech Thanks can I download this without buying ReSharper?

  • @faridmurshudov5796
    @faridmurshudov5796 2 роки тому +1

    Your videos are really great to learn. But please talk a little loud :)

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому

      Honestly, you are one of the few people complaining. Are you sure the video volume is low? 🤔

  • @Tamer_Ali
    @Tamer_Ali 2 роки тому +1

    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  2 роки тому

      You can use whatever you like. There aren't any rules written in stone.

  • @muhammeteser9571
    @muhammeteser9571 2 роки тому +1

    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  2 роки тому

      You're talking about Patreon?

    • @muhammeteser9571
      @muhammeteser9571 2 роки тому

      @@MilanJovanovicTech YES

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому

      @@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  2 роки тому

      This'll save you some money, and give you access to Patreon longee

  • @dvsys751
    @dvsys751 5 місяців тому

    Hi, what theme u use in vs ?

  • @zikkrype
    @zikkrype Рік тому +1

    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

  • @simbatwiga9631
    @simbatwiga9631 Рік тому +1

    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?

  • @malignate4sd
    @malignate4sd 2 роки тому +1

    Just having a handler is not CQRS. You just created an abstraction over a function call.

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому

      Is creating a handler the only thing I did here? What else am I missing? 😅

    • @malignate4sd
      @malignate4sd 2 роки тому +1

      ​@@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.

  • @BlueJay-z
    @BlueJay-z Рік тому +1

    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.

    • @BlueJay-z
      @BlueJay-z Рік тому

      @@MilanJovanovicTech Thanks for the replying.
      but Without CQRS, we can easily to seperate READ and WRITE as well, right?

  • @finickyflame
    @finickyflame 2 роки тому +3

    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  2 роки тому +1

      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 2 роки тому +1

      @@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.

  • @NiamaImia
    @NiamaImia Рік тому +2

    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.

  • @reggyA898
    @reggyA898 2 роки тому +1

    lol World of Warcaft

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому

      What's so funny?
      Classic WotLK, reliving my childhood. 😂

    • @reggyA898
      @reggyA898 2 роки тому

      @@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  2 роки тому

      @@reggyA898 I'm happy that we have similar interests. You'll love this channel for sure 😁

  • @ed-ou812
    @ed-ou812 2 роки тому +1

    CSRQ … research that … cdbc related

  • @fullstackdotnet
    @fullstackdotnet 2 роки тому +2

    A controversial comment... 😂

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 роки тому

      Don't be that controversial 🤣

    • @pilotboba
      @pilotboba 2 роки тому +1

      I fully disagree.
      It's not controversial at all. :)

  • @deedev7279
    @deedev7279 Рік тому +1

    MediatR is bad performance

  • @alexeybeloushko7240
    @alexeybeloushko7240 3 місяці тому

    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  3 місяці тому

      Never seen this approach used in practice. Doesn't it make way for very strange code?

    • @alexeybeloushko7240
      @alexeybeloushko7240 3 місяці тому

      @@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 3 місяці тому

      @@MilanJovanovicTech Patterns, Principles, and
      Practices of Domain-Driven Design by Scott Millett page 701-704.