Clean ASP.NET Core API using MediatR and CQRS | Setup

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

MediatR is cool and all, but please don't use it if you're not really doing CQRS. Putting your CRUD operations into commands and running them through MediatR is not CQRS, it's just an unnecessary layer of indirection making your code more difficult to understand.

👍︎︎ 7 👤︎︎ u/EntroperZero 📅︎︎ Dec 02 2019 🗫︎ replies

What's the name of the sketching tool? Pretty cool

👍︎︎ 2 👤︎︎ u/HydrA- 📅︎︎ Dec 02 2019 🗫︎ replies

I loves me some Mediatr. It changed my code for the better more than any other library.

👍︎︎ 2 👤︎︎ u/andlewis 📅︎︎ Dec 02 2019 🗫︎ replies

Loving mediatR!

👍︎︎ 3 👤︎︎ u/kaisersolo 📅︎︎ Dec 02 2019 🗫︎ replies
Captions
hello everybody I'm Nick and today we're gonna see how we can use the mediator pattern and CQRS in our asp don't recall applications we're gonna talk about the mediator pattern and the mediator package and then i'm gonna talk about CQRS very briefly on both topics because I don't wanna make an in-depth video on these partners I'm just gonna very simply explain what they do you can use any of the timestamps you see right now in your screen to skip those bits if you already know about them so first things first the mediator pattern let's say we have four serviced here and these services need to communicate normally you might have something like this sub service want or service to service let me give me yeah okay so this one talks 2 to 4 2 to 4 to 3 and so on and so forth these services at very much coupled with each other now mediator says instead of doing that what I'm going to do is I'm going to have a mediator object in the middle and every time I want to talk to this I'm gonna go through the mediator and just the mediator knows how we want to communicate with 2 to 3 - with 4 and so on and so forth now let's talk about mediator the package mediator has two approaches it has the request to response approach and the notification approach we know the other about the notifications at all we're going to focus on the request and response and this says that one request has one handler which returns one response so if you visualize this you can have requests one request to enter one and so forth and then you have the mediator here and this mediator accepts those requests find the appropriate handler that needs to handle those requests and each request has one Handler and then this handler does all the magic and returns the response for that request and that's all there is it just does it in a way where you just push the request and you don't know down stream who is actually going to handle this which handler we handless this is the responsibility of the mediator and this is why we use it because it's completely the couple's in our scenario the controller from the application the business logic and all that now on the she q r s front secure s stands for come on the query responsibility segregation and all it really means is that our commands and our queries have separate responsibilities and clear domain boundaries let me give you an example normally you might have you you are here and then you might have your application here and then let's say you have a database here as well so DB and each application internally how's your domain and there is also a data access layer and your UI talks to your application potentially goes the domain and then the domain has done some business logic and eventually this business logic talks to the data access layer which in return talks to the database to do all the magic in the database the problem with that is that everything that mutates or doesn't new type data is in the same sort of domain area and we don't really want that because it can actually couple again things more that they shouldn't actually be coupled let me explain the whole thing looking at a controller which is probably what you're going to be using so here I have a controller and the controller has a few end points and then endpoints are getting points post and points but you might have patch and other things but delete and the list goes on I'm gonna draw a line here I'm going to say that everything let's get potentially head as well anything that doesn't mutate data is so support me type data just as a query for some data falls over to the query R and everything underneath that that post creates put updates delete delete in in the wrestle area anyway I'm gonna classify this the command so as I separated these two I have my application again here so I'm gonna say application but instead of having a single domain layer for everything I have my query model here and I have my command model here so all the commands will go here and all the requests will go here and equally the things that will actually go eventually to the database now for queries because you just do a query you could even have a read-only connection string if you really want to because these are not supposed to be not manipulating any data is just your query domain that's responsible for querying stuff so querying data access layer and the command data access layer this is the separation we're looking for we're not really gonna focus on this side of things but we are gonna focus here because this is where we're gonna use mediator to decouple everything so the ultimate goal for us is let's say I have a get request here and I have a post request here so this gate request will have some sort of query and this post request will be a command they are both going to end up in a mediator and this mediator will find a query Handler and a command handler to handle this request and that way the controller won't need to know for any service is injected into these handlers in fact the services injected here could be completely separated because not everything for this query might be of use for this command and you're gonna see as we're gonna look into the code in just a second this is what we're going for and this is way more manageable and way more testable because you can actually unit test this bit here very isolated from the whole controller side of things because there is really nothing in the controller there's just a query that's being sent to the mediator and eventually lands in a handler but it's a very decoupled approach and very pretty double approach for our application to work so you're gonna see exactly how we're going to implement that now this video is part of my a speed record with CQRS and mediator series so if you don't want to miss any episodes and there are more coming then make sure you subscribe during the solidification but the source for the example I'm gonna show today is on the link down below so make sure you click that as well if you want to get it so here we have our API which only has two controllers it's a REST API and we have the customers controller and the oldest controller and not too much magic in it we have logger we have an oldest repository here in a mapper this is not automata this is just my own custom implementation and then we have a controllers endpoint which has orders and controllers repository it pretty much that's it and I'm not gonna focus on the customers control in this video I am however in the source you're gonna find the link have already translated this to the mediator approach but to save some time I'm only gonna focus on the oldest controller because the oldest controller has both a post and a get so I'm able to show the query and the command approach something worth pointing out is that I'm returning details here and then I'm mapping those details to response objects for the customers to consume so my database objects and my domain objects are sort of decoupled in that sense I should probably have another layer but for simplicity I left that outside just to keep this video smaller now what I'm gonna do is take a look at the other controller and in fact let me just run it and show you exactly what's going on but I'm gonna start with the get all orders endpoint to convert to the see curious approach so here I have the get all loaded endpoint so if I click it I'm getting a single order back but if I use the post to create an order and you can see we created this one then if I rerun this we now have two so the first thing we want to do is we're gonna go to new gate and we're gonna add two packages first we can add the mediator package and you can see the name written down here and on top of that we also going going to add the dependency injection for that package and by adding the package we can just go to the configure services method and say herbs dot add mediator and then specify a type for mediator to scan for handlers so in this and I'm gonna just say start up so with out of the way this will automatically scan full handlers and register them in di now let's look at the controller and we have to get all orders and pulling the talked about we want to convert that and the way we're going to convert the contents of this is by using a query because this is an get endpoint the get endpoints fall under the query approach so let's say query equals new get all orders query and we're gonna go ahead and create a query actually so I'm gonna go ahead and create a new folder here directory called queries and just because we're here we're also going to create one called commands and another one called handlers and in the query 1 we're gonna create a new class called get all orders query and this query needs to implement the I request of type T interface and because I know that this controller will ultimately return an list of all the responses my generic type needs to be a list of order response so we have to specify what this query should eventually return it's very important and now that we have our query we are going to inject an interface here which is very crucial which is the eye mediator interface and I'm gonna inject that from the controller automatically so you can see now that's here and this interface has a couple of methods it has the end let me just show you it has the publish method and the send method we only gonna focus on the send method which is the request response approach and that's what we're going to use so what we wanted to hear really is we're gonna get the result by our waiting the mediator sent and what we're sending is the query that we have and at the end we should just return ok result ideally every single end point in our controller should just have these three lines a query or a command the send method and the result and that's it I'm not gonna eat those yet I'm gonna use them to copy them over to the handler we're gonna create but they are not going to be cold now so what I need to do now is go in the handlers directory and just create a new class and I'm gonna call this class get all orders handler you would also call it get all over this query handler but I'm just going to go with handler and this needs to implement the I request handler interface and first the first generic type needs to be the query that we have so get all all this query and the second one is the response and this is the list of order responses and we're going to implement the missing members and we only have a single method the handling method here I'm going to turn this into an async task because we're gonna outweigh some stuff and now I'm gonna just copy these two lines and delete the remaining code from here and I'm gonna put it in the handler and in fact I'm gonna return here so now we need to inject a couple of things but the good thing is that now we only gonna inject in that handler exactly what the handling of this process needs nothing more nothing less you know we're not logging anything so injecting the logger that's being used by something else was just redundant we didn't need that and we're not gonna do this now because it's very specific it's very targeted on what we're working on so we're gonna say private read-only I orders repository we can automatically inject that and then private read-only I mapper mapper and we are going to inject that as well and as you can see all our errors are gone we now have the handler I want you to see however that nowhere here do we say that explicitly call that handler and I'm glad debug this to show you what's going on so if I run this now I shouldn't need to do any other work for this to work this is all I should do and they add mediator method in the startup should take care of the rest and I'm clicking this get all orders in point and as you can see we hit the debugger so we have our new query and now we're going to set the query to the mediator and as you can see get all orders handler because we send the query defined here in the eye handler interface we're handling this interface we just saying get all the orders I have a single order back and then map it and return it and as you can see we have it here and we are returning it so easy so simple so decoupled and so much cleaner and you're gonna see how it's cleaner in the following endpoints are we gonna change so now I'm should go ahead and do the same thing for the get by order ID and this becomes a bit more interesting because now we have a parameter so what I'm gonna do is I'm gonna go to the queries folder and create a new query called get order by ID query and again this needs to implement the I request interface but in this scenario we'll turn a single order response but we also have a parameter here we're going to create a property which is a good and named it ID and then I'm gonna say good ID ID equals ID and I have my new query here that has a single property which is the ID so and let me just say change below because we don't want anything below for now I'm just gonna leave it as it is and then I'm gonna save our query equals a new get order by ID query but this needs the order ID provided because this query object was a command object later we'll need to contain anything that the handler will need to operate so in this scenario the order ID and then it's the same predictable thing VAR result equals a weight mediator dots and we're gonna send our query a please note here that if you're using a cancellation token it's also supported in the mediator so you can provide here I'm going to be using this in this specific scenario and then I'm saying return and now if result is not null then return okay result so return the order else not found and this will throw an error because we need to cast not found or all k2y actual result that's fine and then we can simply take this and this and delete the rest because we don't need again the same three lines we have a query we send it we get a result back we do some checks and we return so let's create the new handler now get order by ID handler and again it's an I request handler returns an actually accept I get order by ID query the query comes first and the response comes second so order response goes here implement missing members change this to an async task and then of our order we need again to inject a couple of things I'm going to copy them from the other handler and I'm gonna paste them here and then simply use Ryder's ability to inject the constructor and now we need to do request dot ID for the order ID and in fact I could actually rename this to order ID to make it a bit more clear in terms of what it is and then if order is null return null you could write this in a shorthand form but I'm not gonna do that and then just return here and yes in fact we shop just as use of ternary so I'm gonna use that so again very focused very targeted with using the oldest repository if we get the order and we send it back and I'm not gonna test this I'm going to test this when I also do the create or the one which you're going to do right now now here's interesting because as you can see we already have a create customer order request which is a request object coming in now generally you should not be mixing your domain with your API contracts because they're basically separate concerns but for this demonstration I'm gonna actually just use the same object you might want to use separate ones if you want in your production applications so now we have the requests folder here but I don't think I'm gonna leave it as it is I'm gonna cut this and I'm gonna paste it into the commands folder and I'm going to delete the requests folder and now in the commands folder we're gonna find this request I'm gonna change the name space and I'm gonna rename this to create customer order command and because it's coming from the from body attribute so the mapping is happening automatically I need to have public setters for this to work so I'll leave it as this I don't need to do anything so now our command is actually coming from the endpoint and in terms of what we do it's very much the same thing which is calling the command and we say I request and this command returns what do we return here we return an order response which is fine so we're just gonna say order response is a created order we just made so we just have result equals a weight mediator dot send the command and then we basically just copy this line here and we just say result dot ID and result and the rest just goes into our handler which is gonna make now so this is two lines now for our end point so in the hundred I'm gonna say create a new handler I'm gonna say create customer order handler you could very much make subfolders here for our homeless so say query handlers and common handlers but I'm keeping it simple for the video so handler made here I request again in fact I request handler sorry create customer or the command and their response is order response implementing the missing members pasting this code changing this to an async task again changing the request you use that and then we need to inject again a few things in this now we also need the logger and the mapper so I'm gonna copy two of them from the others but I'm also going to say private read-only I logger of type T and the type is a handler and logger and again I'm gonna use resharper to inject those so now everything is injected no errors so I'm returning and everything is nice and tidy where they should be with separate responsibilities so if you see my controller now it's very much cleaner and as you can see none of these classes are no longer needed the only class I'm actually injecting and actually using is the mediator so I can just remove everything else so let's take a look at the controller now we just inject a mediator which is responsible for knowing where things should go to be processed and then we have the create order which has a command and then return something we have the get order endpoint which is a get and they get all orders so if I run this it is in fact running so if I go and get all the orders I can only get one order if I create a new one and I have the ID here as well so I can see them here but I can also do say give me order by ID and this ID is this so everything is working as before but now everything all these possibilities are separated in the next video we're gonna see how we can add validation into the whole mix and how we can use fluent validator to do this very seamless and very cleanly that's what I want to show you for this video thank you very much for watching special text my github sponsors for making these videos possibly if you wanna support me as well you can find the link at the description down below leave a like if you liked this video subscribe for more content like this and ring the bell as well and I'll see you in the next video keep coding
Info
Channel: Nick Chapsas
Views: 162,282
Rating: 4.9501066 out of 5
Keywords: coding, asp.net, .netcore, dot net, core, C#, how to code, tutorial, asp.net core, javascript, csharp, rest api, development, software engineering, dev, microsoft, .net core, asp.net core 3, cqrs, mediatr, design patterns, clean architecture, clean code, asp.net core api, dotnet, .net
Id: YzOBrVlthMk
Channel Id: undefined
Length: 22min 39sec (1359 seconds)
Published: Mon Dec 02 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.