CQS: Method can either change state or return a value - not both CQRS: Like CQS, but not as strict regarding the return value, the main emphasis is on having a clear boundary between Commands and Queries Mediator Pattern: Promote loose coupling between objects by having them interact via a mediator rather than referencing each other MediatR: An in-memory implementation of the Mediator pattern, where MediatR requests & MediatR handlers are wired up during the DI setup Splitting Logic By Feature: Having each use case in a separate file What we demonstrated today is using the MediatR package to implement the Mediator design pattern. We separated our use cases into different files, and following CQRS, we defined clear boundaries between our Commands and Queries by nesting Command Handlers and Query Handlers in different folders. Please remember that the definitions above follow the original definitions of the people who coined the terms, not interpretations of others over the years. Hope that clears up any confusion 🙂
Thanks for sharing. When can we expect next video 🙂 eagerly waiting... Can you upload videos twice a week please 😀... I know this is too much to ask... This is the best content so far on the RU-vid.... Keep it up....
Update on how you should implement the DI in Mediatr starting version 12.0.0: services.AddMediatR(config => config.RegisterServicesFromAssembly(typeof(DependencyInjection).Assembly));
good first steps in the "right" direction, when behaviours will kick in to have logging, transactions, validations, and so on. A long way to go even considering DDD but I'm sure people will enjoy the final result! Just an advice to people who are watching this series (but in general any dev video): after having watched a vid, do your own research on the topic, don't assume what you are actually listened to is good enough or a perfect fit for your needs because things will evolve next episodes and will change a lot of things, also there isn't a silver bullet so it's worth going deeper into the subjects to understand the ins and outs. You'll find yourself changing your approach every now and then: it's a sign you are learning and that's the good thing. The "bad" side is that the learning path never ends :) (actually having to learn everyday is one of the things I like the most about this job and I think every good programmer need to have this approach)
I love the MediatR library. I actually didn’t know you could use just use the ISender instead of the full IMediator to get a slimmed down mediator if that’s all you use if for. Another great VOD in the books!
When I met the MediatR for the first time (at work in one of our projects) I was shocked how beautiful this library (and CQRS pattern of course) is. It makes Controllers so clean and small with no effort. I hope for the 'Notification' part in MediatR 😊
Honest question. But what value CQRS and separating things into commands and queries actually bring? Underneath it's all just MediatR.IRequest - so they are handled exactly the same way by the command bus/Mediator. The handlers ultimatelly don't really differ. Queries, as you said in one of the comments below, can morph into commands, for example when Login Query needs to also update DB with amount of login attempts - it becomes a Command, requiring a refactor which in some cases might be a breaking change. I could see it having some value if it was, I dunno, an interface for repository - where we'd only query data from repository, or update it. But that's usually unrealistic, and Commands/Queries quickly spread into business logic (like here with Login/Create Token requests). Since Commands also return values they are, essentially better Queries anyway. Also can Query Handlers issue Commands and indirectly change values in the store? Or do they need to be refactored into Commands too now? I'm asking all that, because I'm at the tail end of massive refactor, removing CQRS from quite big service, in my company. After few years of development, we realized separating things into Commands and Queries didn't add anything, except for confusion. Queries once created weren't refactored into Commands, if a need arose, Commands sometimes acted like Queries, Queries like Commands, and it all become a massive mess. We tried enforcing restriction, by having dedicated interfaces for Commands/Queries, that restricted what they can return etc. We tried separating business logic into very granular commands/queries, but that become overwhelming - for ex. Authentication - Query for info if user can be authenticated, send Command to update it's attempt number, send query to check if a refresh token is available, if yes, send command to invalidate the token, send command to generate new access/refresh token, send query to get the tokens etc.. This become unwieldly. With so many granular commands/queries it also become increasingly hard to keep track of which are still actually used, as the development progressed.. So now we are throwing it all away, and scaling back the granularity of each MediatR.IRequest. We just have "high level" request send from API endpoint/Controller to a MediatR handler, which handles it, and if it needs more granularity - it sends more requests for other handlers to deal with. That loose coupling that MediatR provides is still there and this is great. But any separation between Commands and Queries is gone.
I was reading the comments precisely for this, I mean if someone thinks that CQRS doesn't add too much value, but unnecessary complexity, and, as you said, queries can evolve into commands depending on the business, and that, for sure, will require a more complex process of refactoring. I'm really enjoying what Amichai is doing with these videos and showing how we can do the same thing. And, for that reason, we can infer what is better to use depending on what we need. PS: Sorry for my English😅
Your video are pure gold! Thank you! I'm switching from Game Dev to Backend development and your videos are helping me a lot. I'm also studying DDD so I can't wait to see more about!
Hi mr:Amichai at 10:05 of the video you miss to say to install the mediatR package in api layer maybe you cat the video during montage. Really really really thanks for your efforts. It's a great series on RU-vid. I hope to talk about Dockers and containers. Thanks again.
When generating a new Auth-Token and saving it in the DB, IMO that does change the State. Login and the Pop method on your Example earlier are pretty much the same thing. Right?
Great video as always. I'm really enjoying the series. Quick question - where should we apply the validation. From your screenshot (at the end of the video) it looks like it should be done in the application. In my opinion we should also validate the request too. Can you please throw some light here ?
I would put it in the application or domain entities depending on the scope of the validation. Validation is one of the core reasons to have a domain in the first place in clean architecture.
Come across your videos recently and they're very good, right content and right pace from my perspective at least. I do have a question regarding the login although this is probably more applicable if the authentication services were self-implemented(which you should never do, of course, instead rely on AzureAD etc.) Something as simple as Login can still have side-effects such as incrementing a failed login count, writing an audit trail, etc. Would these be implemented in the application layer as commands whilst the consumer still regards Login as a read-only activity and is unaware of these commands running?
How easy is to mock the MediatR Send method for unit tests? Im struggling to see the benefits here of using MediatR vs having Interfaces for each CommandHandler and using that. Great series btw! Thanks :)
Same as any other interface 🤓 If you have an interface for all your command handlers you will have to manually wire it up in the DI setup, or do assembly scanning similar to what MediatR does out of the box
@Amichai thanks very much for this EXCELLENT Tutorial. Just a little bit too fast moving code around. Maybe I hope you don't mind publishing the source code so that one can read it offline to see what is going on?. Many thanks❤
Hello sir, thank you for this great video again. I have a question regarding layers. I see that you create a LoginRequest class and then map it to a LoginQuery by using constructor. Let's suppose we have an incoming request body with at least 20 properties; how would you handle these in controller actions? By manually mapping the fields or is there anything I am missing? Thank you again!
I think it is a stretch, calling a "Login" method a query. Depending on your underlying implementation, it MIGHT write to the persistence store. Ie, if you're not using bearer tokens, but actually storing the login i a database. The name Login, is imperative form, and suggests it is a command, regardless of the underlying implementation. IMO "login" _does_ change state not matter what - maybe not in the database, but conceptually the systems state is changed when invoked, since the user is logged in (which he wasnt before), and that to me, is the definition of a state-change (hence its a command) - not nessecarily a write to a persistence store, since that might change over time and is an infrastructure concern, not application concern
I would say, in many cases, yes. We can easily separate logic using Minimal API and inject into every single endpoint different services. Usually MediatR is used in controllers because the last one can have many dependencies but not every endpoint needs them. MediatR allow us to avoid this situation and get less cohesive code. With Minimal API we can reach the same goal without any overhead and additional code. Some people are used to use MediatR and still use it whenever it is possible. Sometimes they as if they refuse to understand that it does more harm than good.
Is there a reason you don't use the Query and/or Command as the action parameter? That's pretty common in other templates and examples that uses these patterns.
Even though it saves the mapping in the controller - Yes, a few reasons: 1. In MS (and I'm sure other companies as well), it's common to publish the contracts project as a NuGet package. Then, clients written in .NET can consume it instead of redefining the same models. It also plays well with versioning, where you would simply consume the new version. 2. Commands/Queries aren't always an exact map of the request. A simple example for this is a PUT endpoint, where the id comes from the route. The command would have both details from the request body and the id from the route. 3. It decouples our use cases from the API definition. Want to change names/add properties to a command or query? No problem 🤓 Does that make sense?
That's great and what we have done, but plus that i'd rather to split persistence layer from application layer. So that the logic and db operations would be separated. 👍
Hey, always waiting for your next video! :) How did you do the replacement in 5:55? -> Answer is the "Vim Emulator" Extension with the command seen at the blue bottom bar And who can there be a base construct in 11:47?
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'
What benefit we get of duplicating a request and then same props in command or query. Why can't we just use command or query directly as param to Api. ?. This will save some boilerplate code. like LoginRequest and LoginQuery will have same props according to this video.
great tutorial, but due to such elaborate classes and structures, people hate java/c# and are preferring much simple golang, which also provides better GC than java.
I didn't get your magic tricks when you install Mediator into the Application project and adding Mediator library from Api project. But Api doesn't have installed mediator library. Or the whole job do Git Compiler?
You can use both. The handlers can use your repository interfaces that are implemented in your infra layer. So, it's not an either/or, they are sort of different concerns.
Great video again :) I like this ideo of splitting by feature. Would you reintroduce a service class again to handle common functionality between different endpoints? And I haven't really understood what the benefit of splitting the contracts project from the api project is. Can anybody shed some light on that?
it's just preference for him I guess. If you are fan of multiple classes in one file, you can put each of these classes from /Contracts in the files where the controllers that use them are defined, so you have everything you need in one file. If one really decides to organize by feature (vertical slices) and not technical concerns (horizontal layers), having everything you need for a feature in one place might be the handiest approach: controller, request, response, handler, validator etc. You can even have the UI that is related to that feature in the same folder :)
We are using CQRS and IMediatR. In cases where a multiple query/commands must reuse same piece of code, is it ok to call another query/command inside query/command handler or the same code should be extracted to a service and injected in the handler?
In the past I've used the Command Pattern as described in the GoF book to facilitate Undo/Redo in MVVM applications by keeping a list of all the command objects. If I was building a web app where I wanted a Rest API and Blazor App for different Presentation layers, would there be any relationship between the GoF commands and the CQRS commands? Could CQRS help with Undo/Redo?
CQRS said that you need to separate Command and Query to database, but in the Register you still need to Query to check user email exists or not. Can you explain is it right when apply CQRS or not
Hi, I love the MediatR but I have a problem with it. We can say that the MediatR handler replace our Services Layer. What happens when a service needs to call another services? Jimmy Bogard discourage calling a Mediatr Request from another Request. what is the solution to this problem? reintroduce a service? Thanks for your help
I assume that if for example registerCommand & loginRequest both required some common functionality, that you would create something like an authenticationService again and use that in the requestHandler. Just my best guess though.
@@richardhaughton9633 Mhh, imo it wouldn't become a 'god' class again because it contains only methods that you need to lift out of any single requestHandler for re-use. Similar to how both requestHandlers use the tokenGenerator.
@@TheFeljoy For example let's say I have a CreateEntityRequestHandler that Handles a CreateEntityRequest. Let's also assume that I have an ImportRequestHandler that handles an ImportRequest. When the ImportRequest detects a new Entity it needs to create it. Should I call the CreateEntityRequest and Send it through the MediatR from the ImportRequestHandler?
@@richardhaughton9633 No. You could create a new class, say a repository class that handles the creation of entities in the system.. now you can just inject that class to your CreateEntityHandler and ImportHandler classes so that you could reuse the logic in multiple handlers..
People understand mediator as a CQRS pattern, i totally disagree with that. ISender interface wraps Command pattern and it is not about CQRS. It is about request handling per use case,(clean architecture stuff..) IPublisher interface is for in-memory message handling. Normally CQRS is about persistence layer. But, for domain centric projects(you can use DDD) sometimes you need different components for handling that. Every state change on domain could raise a domain event. For that reason, we can use CQRS. It could feed other domains or own query db with that. Also, i think login is a special case and it is not a query. It can generate(also needs HttpPost) a token for that given user. Normally, it is not changing any data on persistence layer but you could persist some columns like last_login_date or device info when business needs. When you login a user, you keep him/her in play. So, user with role is in play for a limited time. When you refresh this token, you gave extra time for that user. For jwt, we don't persist to db, it is in memory. But, also that token contains changed user states which is an authentication result.
Perhaps I could have been clearer regarding the different patterns we used. I've summed up the details the pinned message 🙂 Regarding login being a command or query, I agree it can definitely be a command as well. I prefer defining flows as queries if they don't change any state, but like everything, it depends on the implementation and person taste. What do you think?
I've been thinking lately about Azure functions vs web apis. Cost of Azure functions are pretty low comparing to web apis (up to a certain volume of triggers/queues). Web api requires an app service which has an uptime up to 93 - 98%% according to azure datacenters. If its cheaper and you can easy achieve seperation of concerns? Does anyone one know why and when you want to choose the one over the other?
I have an issue with vscode, I don't seem to have the option to "Change namespace to match folder structure" and it is really annoying. Do you know is there a fix for it ? Btw, great searies I really enjoy it and learn a lot, actualy you have inspired me to switch to vscode 👍
Congratulations on the article Amichai. Let me ask you a question. You don't think using mediatr for the query stack is creating overengineering. Since one of the ideas of CQRS is also to speed up and simplify queries, by using all mediatR objects we are not creating unnecessary objects and instantiating classes that also have a cost. And classes without arguments is quite common, it's just being used to orchestrate to the right handler. Shouldn't we just go straight to the data source? sometimes I get the idea that we create a lot of unnecessary objects for queries.
Awesome explanation and content. If a part of the code that is defined in a Handler has to be used in another Handler, what should be done? Create a service and encapsulate that functionality so as not to repeat code?
Depending on the duplication you encounter that might mean that 1) you got your logical boundaries wrong or 2) you indeed have to extract that functionality to separate service/domain service/domain entity.
In .Net Core 7 with version 12 of MediatR on file BuberDinner.Application.DepencyInjection: services.AddMediatR(x => x.RegisterServicesFromAssemblies(typeof(DependencyInjection).Assembly));
One question Amichai: If we also want to update the user's last login DateTime after each login, our login is still a query or a command? How do you separate these two functionalities?
Hi Amichai, while using CQRS pattern, shall we need to create class for every query? for Ex: Domain Entity ( Order ) I need queries like GetCustomerOrders / GetPaidOrders / GetCanceledOrders / GetOrdersPaidByCreditCard and also complex queries using Store Procedures(for KPIS / Reports ) So for every query / Stored procedure, we need to create separate Class ??
I don't understand. What happened to old-fashioned Interface extraction of the data for the ViewModel Why am I adding a stupid library for extra download for no good reason? You can create a ViewModel Folder and each entity, create a folder for itself, and create the interface for it. CQRS, something, Create a folder under the same repository and call one of them Transactions or whatever you want to call it to make it clear, and the other one Query. let your services call it accordingly. Make it clear. You don't need all these things and make your code bigger and bigger by adding unnecessary libraries.
Thank you so much for the videos, I love them, however, it fails to highlight one key aspect which is, you failed to make us beginners understand what problem the MediatR nuget package is trying to solve or why we should even use it. I think explaining the problem the package solves would help us appreciate it and know when to use it and even come up with other impelementations. Again, thank you for your videos and I love them.
Hello as usual, very nice video, but there something I don't understand. At 9:30 you install MediatR package to the application layer. But just after you use IMediator in a controller (from Api project) how is it possibe? do I missed something. Because in my environment if I want to use a library un a controller, I need to install this library in api project.
Thanks. In clean arch, outer layers have a dependency only on inner layers. Since the presentation layer references the application layer then it's available.
From the projects I came across, most became really hard to navigate once the shared "building blocks" become generic to support the various modules. Perhaps for devs who are aligned on the architecture it can be super convenient, but it can definitely add another layer of complexity above a single project similar to the one we are building which already can be tough to onboard. Does that make sense?
And, you don't need any mapping software as well. What is going on? Why are we adding these libraries where you can do it yourselves easily and your project size will be smaller? Are we trying to accommodate not-so-good programmers? Is that why we are having too many hacks?
Why are you separating command and query outside of IAuthenticationService? No code outside of the implementation cares. You're introducing something and a LOT of code that doesn't matter. The implementation of authentication's repository (maybe IAuthenticationRepository) might care because there is a read side and a write/transaction side, but not at the front end or what should be a very thin, single line, of code in the controller. Oh, and what happens if login requires a counter update to restrict failures every n minutes? Also, even query commands will/might update the log database, but I guess that doesn't count. Sorry for the rant.
This goes so fast that it's annoying. Indeed, you know how to do it well, but please go slower, especially on the shortcuts, the contextual menus, and the change of files. You'll become a great YT teacher. Good work!
I'll keep this in mind for the future videos, thanks for the feedback. I'm thinking of specifying the difficulty level in the beginning of the video so viewers can adjust the playback speed accordingly.
I really appreciate your videos and the way you explain everything, but... I'm struggling to finish your videos when that "yeeeeessssss" is repeated all the time.
Cool. I have been working with CQRS and MediatR a lot and it's hella clean and works very well with FluentValidation, other/custom middlewares, integration tests and in general with DDD. I've been only wondering why would you register MediatR (or before, without MediatR, your services) in a separate DependencyInjection class and call it in Startup.cs/Program.cs instead of just calling AddMediatR() directly in Program.cs/Startup.cs? Your API layer needs to reference Application, anyway, so what's the point? To keep Application dependencies setup code in Application layer? Wouldn't it be cleaner to create a private method in Program.cs/Startup.cs directly e.g. RegisterApplicationDependencies(serviceCollection) and keep all the setup in one place? I've already seen people going the extension class way and then registering the same thing twice in two different classes, in two different ways, once in Startup.cs directly then in an extension method again because they couldn't keep track on where everything is registered when it's so split, especially developers who didn't write that particular piece of code. What's the gain here?