.NET 7 💥 - Intro to CQRS and MediatR with ASP.NET Core Web Api

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
foreign thank you for watching this video I am Muhammad and today we're going to be discussing something really interesting when it comes to building.net apis on.net application which is going to be the mediated pattern and secure us we're going to be going through the theory of how we can actually implement it and why do we need it and how does it work and then once we have covered the theory we're going to go through implementation we're going to be seeing step by step how we can actually implement the cqrs and mediator pattern we're going to have seeing how we can actually upgrade our controller to take benefit of that if you like this video please like share and subscribe it will really help the channel as well if you'd like to support me please consider supporting me on patreon or buying me a coffee now with that said grab a cup of coffee and let's get started so before we get started implementing cqrs and the mediator pattern inside our code is really good for us to understand why do we need them and how do they work so in this example right here what do I have I have different services so let me try to name them so for example this can be our the service one here this could be our mediator service or sorry this could be our RTP context another is one could be for example here our logger we can have a third-party service for example we can have our unit of work we can have here for example another third party and another third party for example so as we can see here that all of these services are directly interconnected with each other so what means here like service one needs to know about service five and how does it communicate with that does need to know how everything is connected so we need to make sure that it has the right dependency injection so on so forth similar to service 2 when it comes to service four five and six service three service four five six etc etc so all of these services will basically need to understand everything about all of the other services they need to know how they communicate with what do they need in order for them to initialize them what are their dependencies and all of this information so every single service here will need to know about all of the other different services so for example service one you need to know about three services service two or three services etc etc so as we can see here these services are directly coupled together there are a lot of interconnectivity and Inter direct tightly coupling together and for example for a very small project that could not be a problem but as soon as we start scaling and added more functionality adding more services having all of these tightly coupled together is going to start creating out of issues when it comes to testing credibility will be complicated every single service will need to basically and if we add for example here server seven and we want to utilize it within service two and three so this means that we need to reintroduce uh how this community how these Services work so basically what does this mean so we need to update all of those interfaces within those services so they will be able to communicate with this service and then thus is going to create another layer of interdependencies between them and it's going to create a lot of different problems when it comes to handling all of these interlocked and these dependencies between these services and as we can see this model here is really not really very scalable because it's gonna create a lot of fairy tight coupling and handling these type couplings can become quite complicated very quickly so this is where the mediator pattern comes into place so basically a mediated pattern takes and remove all of this complexity so what do we have here is a very simple approach so instead of service one knowing how to communicate with service 6 service 5 service 4 Etc et cetera or the service one needs to do is just tell the mediator I have this request and I want to communicate with server six and this is the information that I want to send the mediator will take the request figure out what server 6 needs in order for it to actually work and then it will propagate the requests if service 2 wants to communicate with service 4 again similar pattern there the request will go from service two to service to the mediator it will tell it what does it need it's done the mediator responsibility is to actually figure out what are the requirements to communicate with service holds what are the dependencies all of that and then the mediator will provide it and so on so forth so here we can see is we went from this spiderweb of interconnectivity and interlocking between all of these different services and the tight coupling into something which is completely distributed and basically less complex because we have removed all of the reliabilities that every single service needs to know everything about all of the other services and what we did is We have basically made the mediator as the main pipeline in order for us to actually handle the requests between those different Services the mediator here is playing a key role in actually propagating the requests between one service to another and for example if service to Once wants to communicate with server 6 server 6 all it does it need to do is just send a mediator request and do that so if we introduce for example a service service 7 we don't really have to worry about making sure all of the other services are aware of service 7 requirements and how do they work all we need to do is just to make sure that the mediator is aware of it and that's it we can utilize any service from there in order for us to communicate with service 7 and so on so forth and we can see here the power that the mediator platform provide and why do we need it in a service based approach because the level of complexity that non-mediator will provide us just can't be drastically big so this is a very high level overview of the mediator we're gonna go into a very deep and low level implementation so we can understand how we can implement it within our applications but before we do that let us now understand the types of the requests that the mediator provide so we have two types of requests that the mediator provide there's the notification and there's a request response a notification part we're not going to be delving into right now if you're interested in the notification part please let me know and I will create a different video about it in today's video we're gonna be focusing on the request response and what does this mean so a request response means that whenever a single request comes from one service to another there's some kind of a Handler that the mediator have in order for it to process that response so what does this mean if we take a look at this one here we have service one and this one service one wants to communicate with server six so the request will go from service one let's just make it an green so we know what is the request coming here so service one wants to communicate with server six so service one will send the request server 6 which is solid to the mediator the mediator done what it needs to do it needs to find something called the Handler we're gonna explain what the Handler is later on but it's basically a way where the mediator actually recognized the dependencies for service six so I'm just going to call a Handler so the mediator will find a handle that's going to be using once it finds the handle for Server 6 then it's going to actually allow the communication with server six so it's going to be something around those lines so we're gonna put one also this is the initiator so this is going to be the first part and then it's going to go to the mediator the mediator is going to find the Handler and once the handle has been found we can actually oops we can actually trigger server six and get the response back and then lastly so one two three four and lastly we're gonna get back the response so here again lastly we're gonna get back the response so because it's going to go all the way back through this so this is the request response so it's going to go from the surface to the mediator and here we can think about the handle it's just a way where the mediator you is basically a service that a mediator use in order for it to figure out how to communicate with service 6. and here as we can see again within any request once the request comes in it will find the handle for it so the mediator will find its Handler and then it will send back the response again similar implementation so here for example for every single service we're gonna have its own Handler so request one will go to the mediator it will find the handle for that service and then get back the response similarly request 2 etc etc so again we're removing all of the dependencies that we need if you don't really understand the handle right now we're going to explain it much more in details in the code but this is the high level overview a hundred is basically a way where the mediated pattern rely on in order for it to actually understand how it utilizes server 6 service 6 in order for it to find the data that it needs so now that I've understood the high level of a mediator and its implementation it's really important for us to actually understand right now cqrs because you can work with mediator by itself but basically also it will be really good to use mediator with the cqrs pattern and we can see how those two work together and in order for us to have the better approach so if we go back here let us understand what does the word cqrs means and secure s is a pattern which stands for command query responsibility segregation and this can mean a lot of things um if you're not really familiar with it and it can seem a bit complicated but basically what we can think about it in a way that we are separating the commands and the querying into different responsibilities as simple as that we are basically trying to remove the complexity of handling any commands and any querying two different responsibilities documents here it's going to cover a wide range of items which we're going to be delving into and the querying here is basically thinking about it in a way where we're actually asking the service in order for us to do something rather than trying to update certain types of information so I know that doesn't make a lot of sense but that I see this in this example so in this example here we can see that we have a client and this client is doing some API calls the API is basically responsible to process that request send it to the database the database will result will send back the information then the database that API will process this data and then back to the client so this is a fairly straightforward API implementation where we can actually see here the full pattern or basically the full life cycle of a requests so without cqrs this is can delve into this types of operations so every single endpoint within our API that we are seeing previously is going to come through our controller and within that controller we're going to have the main Cloud operation we're going to have a create read update delete we might have a put we might have a patch we might have the HUD so on so forth so we can have a lot of different uh requests types when it comes to our controller but basically when this request comes in from our clients it's gonna go to the main API it's going to go to The Domain first and then the domain is going to be responsible for actually sending that request to our data access layer then through our data access layer it's going to go to our database then it's going to go propagate back from our database we're going to get the response through the data access to the domain and back to that client so here we can see basically all of these types of requests that we are actually coming in is handled by the same domain and this same domain connect to the same data access layer that actually connects to the database and here we might actually start seeing the problem although this implementation is fairly common for a small to a bit medium implementation but this can create a lot of different problems the more that we want to scale out our application and have a better separation of concern but the stability so and so forth why because let's say for example I have I'm running some kind of a new site and let's let's try to do it here so I'm gonna create some spaces here on the side and let's explain it so let's say I'm trying to create a new site and within this new site I have let's say 15 journalists and this 15 generators are responsible to doing the four crowd operations that we currently saw so let's just let me copy it from the other screen so these four journalists are basically only doing this creating updating reading and deleting new stories which is fair enough so these journalists are have the capabilities of doing all these scrub operation on this new site which is fair but this 15 journalists are only actually doing all of this implementation now let's think about the public itself so the public itself as I'm sure like everyone here in the morning they just checking the news it can go from one single individual to hundreds of thousands of people actually checking the news it depends on how popular your site is but let's say it's a very popular site and basically all of these people will not have the capabilities of actually updating deleting and creating the news so for the 15 journalists they're gonna have all of these capabilities needed for them and within that approach that we currently had which means they are going to have access to the domain the data layer and the database but for the other people so which is going to be the news readers here for this news readers they will not be able to have access to the create or they will not have access to the update or the delete so all the newsletter will have access to is simply the read while on the other hand the journalists will have access to the create they will have access to that it as well they will have access to the update and they will have access to the delete so that means let's make this like this so we know exactly which is what so let's make this different color so this one let's make this uh purple okay so now we can see where the problems lies and because right now we have all of these conductance coming into our applications and all of these connections are basically relying in the same implementation on a single domain and then on the synthetic data access layer and then Connect into the database but for example for our news reader we don't really need to do we don't we don't really need to have the update and delete and create available for them because they don't need it they don't have access to do it only the journalists who actually create the news will have actual ability to create an update and delete news and this is going to be the main thing here we need a way where we can actually try to segregate these requests into the read which is only going to be utilizing querying the database for information getting it rather than trying to do any types of command on the database and trying to update the information creating it and deleting and so on so forth so this is where cqrs pattern come into place now let's see how this model will transform a secure us within a secure asks what we're doing here is we are actually separating the main code operation what we're doing is we are actually breaking down the cloud operation into two main section where the query which is going to be the read command here because basically we are querying the data for information so I can say this is going to be the query part the querying part which is going to be this one let's just make it like this and I think it's here yes so this is going to be the query part and we're gonna have the command part who's coming around all the way from here to here foreign here is going to be I basically allow us to execute some kind of command on the database like basically create updating and delete so we can see here that we have those different implementation we have two different layers that the application will need to be to be able to to process and then that will go into our data access layer we can see we have two different data access layer one the data access layer which is completely responsible for the querying another data style which is only responsible for the commands and they're gonna speak with the database now this implementation seems to be almost identical because all of the uh when it comes to the communication of the database because all of them goes to the same database a better uploads to handle this is have different conduction strings so we're going to have a unique conduction string here for the data access layer for the querying sorry and another connection string for the command and this will allow us to have a full separation of the processes that you actually need in order for us to actually execute so the read request is used is the last taxing on our database but on the large quantity we need to have its own unique implementation or basically separate server service or and handling all of this data requests because they're going to be quadrupled the size so rather than 15 we can have hundreds millions of people who's using the site to get the news on the other hand for the create update and delete one can have a few like journalists like 15 20 50 even 100 or a thousand it's going to be less than the millions that we're going to be seeing for the readers so it makes sense to have different connection strings to have different way to connect to the database based on the types of action that we're currently doing and this is where CQR has come into place a segregation of these two request one for the query which is actually only reading the data and the command which is going to be create updating and delete and this pattern here that we currently see is a way where we can actually if we want a unit test the querying by itself or the commands by itself we can do that if we want to do stress testing it will allow us to do that chaos testing it will allow us to do that I'm not saying that those are the other ones will not be able to handle all of that but this one will be able to actually give us much more of a right approach or basically right information about what's going on inside our services when it comes to handling heavy load because you are actually able to see what is the main weak point for example inside our queries that we're trying to get out of the database or inside our commands would have to have a better visibility on whatever is going on inside there so this is a very high level overview again of cqrs and why do you want to need it so as we can see here the difference is we are actually separating the main Cloud operation from between the create read update and delete to actually read and this is going to be the main query and create updated as a different items that we are going to be handling so this is the full level overview so now for the implementation we're going to utilizing the application that I have built in the last video it's going to be simply a cloud API that I have created if you're interested in following how I created that I will link the video here and in the description down below and we can start from there but this should work with any API that you currently have as well and all I'm going to do here is just run it for now so this is the application that we created previously as you can see here that we have a simple controller which contains drivers information and then we have the achievements and we have basically a very simple SQL line database that we're utilizing as well here we have our program.cs and we have separated the data service and added into different projects again more details about this in the previous video so please if you're interested feel free to watch it so you're able to follow on exactly but this will work with any types of application or DPR certificate they have as well so let us run this and see what do we got now this is running we can see here that these are the different endpoints so for the driver we have a photograph operation where we're actually getting the driver's information delete post put and get all drivers so let's try to execute this right out execute and here we have only one driver currently which is Sir Lewis and if we take the driver ID and we try to see the achievements so we can actually post an achievement updated and get it so if we try to get an achievement based on the driver ID were able to get the achievements here okay perfect so now that we are 100 sure that our application is currently working as we need to let's go back to Rider and see how we can actually start implementing it let's take a look at our terminal because we want what we want to do is we want to start actually creating and adding some packages and the first package that we need to add is going to be our mediated package and it's going to be.net add package mediator and we can see it has been installed successfully and to verify that has been installed we can check our cs plus here and if we go down here we can see that the mediator pattern has been installed and something that I want to know the current intermediated pattern is on version 12.1.1 so any version of the mediator pattern after 12. this is the only package you need before version 12 there was a different package for dependency instruction that you needed to also install this is not the case anymore within version 12 but just for your awareness if you're using version anything before version 12 make sure you install the other package and if we go back to my web browser let's try to find it find it so Google you get package mediator so this is the one that we have currently installed but if you go back this is the other one which as you can see has been duplicated but this will work with anything before version 12 so make sure that if you have anything before version 12 make sure you install this one as well so you are able to actually utilize dependence instruction with it so now that we have that has been said let us go to our program.cs start updating it in order for it to utilize the mediator so what I want to do here is a gun before we build the app what one does one add Builder dot services and here what all I'm going to be doing is I'm going to injecting the admin the mediator package so add mediator and now what I wanted to do is I want mediator to be able to scan my entire dependencies and to actually able to figure out the DLS that current existed in order for it to Bear actually able to scan and create and review the handles that it needs to and try to identify the requests and so forth so to do that I'm gonna utilize my configurations and I'm gonna say configurations Dot register service from assembly and then here I'm just gonna put type of and program and let's fix this so there's a lot of different brackets that we don't need so let's remove one and let's remove this so we have two yep and then what I'm gonna put here is the assembly and then I'm gonna close it so this one should be here we need to close this one and then this uh we don't need this one let's remove it actually we do okay perfect so now it's actually working and this is the line we're gonna be needing so here we're injecting the mediator to our Di perfect again all we're doing here is just starting the mediator to scan all of the assemblies that the program.c has because it's going to be the main entry point in order for it to be able to utilize it so what we want to do here is we want to implement the mediator to our drivers controller and within our drivers controller if we take a look here let me just make the smaller if we take a look we have the gut which is going to be the first one and then we can here we have the post and then we have a put we have another Gap let's put the gut next to each other so it's easier for us to do this separation and again here we have the delete and what is the post that's the post okay so we have post and we have the delete and together okay perfect so these uh controller endpoints are basically a simple record operation that we have seen and as you can see through all of this for every single item inside our controller we have a lot of logic going on so for the get all driver it's quite simple we're basically calling the unit of work they got all the drivers and then we're returning the response which is fair enough for the drivers I get a bit more complicated where we're actually validating the input request and then basically from there we are mapping it from a dto to the database entity and then we are adding it into our application into our database and then we're saving it and then we're returning the result so we can see a lot of items is going on here in order for us to get this response so what we want to do right now is we'll start implementing the mediated work step by step first of all on the gut and we're gonna start separating the logic here and have the mediator to be able to handle all of the queries which is coming in part of the cqrs pattern and the mediator will be able to handle all of that so let's see how we can implement this so the first thing that I want to do here is inside my root application I'm just gonna add a new directory and I'm gonna call this queries and inside my queries I'm going to add a new class and this class is going to be called get all drivers query and yes someone added so the idea behind this here is I want to have a directory where it's going to be handling all of the queries that the application might handle So currently it's going to be for the driver this can be organized in a and a bit more sophisticated way but for the simplicity's sake in order for us to make sure that everything is simple as our first implementation for security we're going this way so once I do that what I want to do here is I want to inherit the eye request for mediator and basically the I request here it's gonna tell the mediator that it's gonna have a request coming in that it needs to actually figure out the Handler for it and basically once I'm getting this query if we remember from the design let's go back to the design if we remember here basically every single request that a service will make is being conclusive a request so basically what I'm identifying that this is going to be a mediator request so I need to inherit from that request request class that the mediator will provide and basically what I want to do here is I want to specify the type of request and in this case it's going to be that I got all drivers query I don't want to specify the type of response and if we go back to the driver's controller and for the gut all drivers we can see the type of response is an innumerable of driver which is going to be this one here so let's get a new mobile driver response and this is going to be my response type and basically right now what I did here is I created the request for the mediator so this is the first part and I specify the type of response but I did not work on the Handler yet so that's something that I have to do next but for now what I did is I just identified that request so let's put this here for this request I have to find first of all the type for it so let's just make it smaller so type we said it's going to be a query because basically I called all driver queries that's the only way I told it uh it's not related on the convention it's basically a way because it has a very simple implementation here I just did the I request for it and then we specified the response type and here's gonna be a list or I enumerable let's make it less because actually let's put in unable to be more accurate let's make this a bit bigger perfect so now this is what happens when I created the request so first of all I identified this and let's add this here okay perfect okay so now that I have created my request I was able to identify it this request by itself is not gonna do much because it needs other parts of the mediator in order for it to work so let's see how we can actually build it I'm gonna just mark this as green now here as the request now what you can see here after the request I need to create a Handler so now within the hundred I need a way where we can actually identify which is the type of query that I have and actually process it so inside my root controller here I'm just going to create a new directory and I'm going to call this handlers and inside my handlers here I'm gonna create a new class and I'm gonna call this class get all drivers Handler perfect and basically this got all drivers query is going to have its handle which is going to be here and it's going to be called the get all driver sanding but having this query by itself it's not going to be enough what I need to do is I need to inherit different items from the mediator package in order for it to actually recognize that this query and this handle belongs to this query so let's see how we can do that so here what I need to do is I need to inherit from the eye request Handler I need to specify first of all what type of request that this Handler will handle and I'm gonna put the get all driver queries and then I need to specify again the return type so if we go here to other driver queries we can see that the return type here is going to be the I enumerable so I'm just gonna put this here and I'm gonna have to fix those references perfect and now it's complaining because we have not implemented it so let's implement the required numbers and as you can see here the only members that we have is a handle function which is going to be allowing us to handle the uh what we have we can input the logic that we need in order for us to handle this requests so again what we did here first is we created the query and basically we said that we're going to have a query type and it's gonna return a Hydra I enumerable and we specified it as a request coming in and then what we did inside the handlers is we just inherited our basically the I request Handler and then we specified the query and then we specified the return type So currently here inside the request so basically first of all we specify the query so let's just copy this and here we put query and then we have specified the response just to make this more accurate he would not specify your type it's just based on Dynamic convention so all we did before the request is just specified the response on the other hand for the Handler we have specified the query and we have specified that response so this is I'm gonna make it in different colors so now that we have specified the request now we have created the Handler what we want to do right now is we start implementing it so an easy way for it to implement it let's take a look at what are we doing here inside the get all drivers controller so inside I got a driver's controller we are relying on the unit of work service to actually call the a database and basically we're relying on the automaper in order for us to map the response so we need these two so in order for us to utilize them what I want to do is I want to go to my base controller and I'm gonna just copy these two actually let's copy all of it and we can update it and let's go to the drivers Handler and basically what I want to do is I want to check this here so now basically I'm injecting those two Services inside my Handler so the handle will be have access to the unit of work and auto mapper and inside my driver's controller I'm just going to remove all of this logic that currently exists here actually yeah let's just operated so it makes it easier for us so I'm gonna put VAR s results again this is we can call it whatever we want and I'm just gonna make this like this and I'm gonna return the driver's result and now what I want to do is I want to take these and put them inside my Handler so if I go back here to the Handler and I can put them here because now as you can see that this is taking it so I'm just gonna put as an async so it will actually recognize it and what I want to do is I'm just going to return the results from here return so now what I'm doing is let's make this private and private okay so what I'm doing here is I'm just handling the request I'm putting the logic of the get all drivers requests inside my Handler so whenever a request comes in and the hunter needs to identify how it works is we're actually adding the logic that we need to in order for it to recognize and I think what you can see here I think what you can see here is why do we want to use that because you can see the logic of executing the request is not directly linked to the controller anymore we have a handle who's responsible to identify all of the dependency which is needed which is in this case going to be the unit of work and the auto mapper and we're not relying on the controller to do this heavy lifting we're dedicating this work to the Handler and the handle will be able to do to do this and as you can imagine this will make it much more easier to do unit testing it will make it much more easier in order for us to scale this out and it's going to be basically a better up close to 100 within our apis so now let's see how we can complete the full circle so now that we have done this we have added the query we have added the response type and we have added all of the logic that's needed so the logic for the uh for the query here so all of this has been completed now what I need to do is I need a way from inside my driver's controller where I can actually rely on the mediator to actually pick up this request and this is going to be a straightforward to implement so let's see how we can do that so the first thing that I need to do is I need to inject a new I need to utilize the mediator Library so it's going to be private read only mediator and can call it underscore mediator and then I'm gonna inject it here so I'm gonna use Rider to initialize it for me perfect and then once I have done that I'm gonna go to my action here and inside my action what I want to do is first of all I want to define a query so far query equal new get all drivers queries so basically what I'm doing here is I'm specifying the query that I have for this endpoint so this is going to be the query that this endpoint will handle and then what I'm doing here is I'm going to put VAR result equal await underscore mediator dot send query and that's it and then all I'm gonna do here is sort of driver result I'm going to return the result so what happened here so I specified the query that I have which is in this case it's gonna be as simple as telling it it's gonna be a incoming request and it's got a turn time is going to be of I driver response and that's all I did within my controller because what I did what mediator does here it will actually take this query it will actually send it and it will send it means that it will process it and what the mediator will do is gonna do a mapping of the entire handlers to see what does what which request it will map into so if you noticed we did not specify the direct Handler for this query but because inside my Handler folder I have specified that this handle I created belongs to this query Auto map sorry the mediator is smart enough to actually recognize that this is the handle for this query and it will automatically execute it for me so I'm not gonna be responsible to specify which Handler to which a query this is the mediator stuff that was going to be doing for it for us in the background and it's going to do all of this mapping for us so what we have done here is we have specified the request we have specified the Handler and then finally we got the response so again it's it's it might seem a bit uh like magic of why did we know how does it know about the hand and so on so forth but all of this is happening in the background and the mediator is actually doing all of this work for us so here what I want to do is just I want to run my application and see this in action to see if we're actually able to get the response so now that it's running I'm gonna go back to my web browser and I'm just gonna refresh this and get all drivers I'm just gonna click try it out and execute and as you can see here we got all of the responses back and what I want to do right now is just kind of put a Breaking Point to see what's happening so again I'm gonna execute this again and we can see here we hit the breaking point and we can see here from the query we basically because calling the code or traffic does not contain anything all this is basically inheriting the I request from the mediator pattern and then once I click on send uh I understand I'm just gonna put in Breaking Point here so we can see that how the mediator is automatically using this so if I just continue running it so I'm gonna put resume and we can see that the breaking point had the right Handler that we have and basically it was able to figure out that this is going to be returning the list of drivers and currently I have one and then it does the proper Auto mapping for it and then it returns back the response so all of this is the response here so all of this is basically handled by the mediator and we can see here how if we go back to our drivers controller how is much more less busy our endpoint it's gonna be only three lines and within this three lines we are able actually to execute everything so now what we're going to be doing is we're going to start implementing this for the gun driver as you can see this is a bit different because here we can see we have a driver ID that we want to pass so we're gonna see how we can Implement that but once we do that we can see that the how the logic that we are actually implementing is shifting from our API sorry our from our controller to our Handler and here we can see it has good separation of concerns that we need to actually follow so to implement a driver query I'm going to create a new class and I'm gonna call it got driver query again I have to inject from the I request and I'm going to specify the return type so if I go here we can see the return type is can travel response and I'm gonna import the reference and this is basically the first step but this is not enough because if we take a look on the controller we can see here that I have driver ID and what I need is I need a query here actually to recognize that there's going to be a an idea that it needs to actually process in order for it to work and let's see how we can do that so first of all I'm gonna create a private good driver ID and I'm gonna make it as a gut and then I'm gonna put a Constructor and then I'm gonna initialize it through the Constructor and basically right now what I have here is the driver not the dryer driver so now that I have this now basically my query right now is able to recognize that there is an um so once this has been done now I need to go back to my handlers and I need to create a new Handler I'm gonna call it the get driver Handler and again we're gonna follow the same structure that we had before I'm gonna inherit from the I request Handler specify the query and specify the response type so I'm gonna go ahead I'm gonna put my request Handler and the request is gonna be the get driver query and the response type is going to be I think the get driver response yep and again it's going to require us to implement the missing member which is the handle let's make this async from now and just for Simplicity sake I'm just gonna copy these a unit of work and I mapple from here and just put them here and update the Constructor name okay perfect and now what I need to do is I want to implement this handle function here so if I go to my driver's controller or for this get old driver what I'm gonna do is I'm going to take this and I'm gonna put it inside my Handler so first of all we can see here that we are not able to find the driver's ID which is fair enough how can we access it it's pretty straightforward because I have my request I can directly tap into the why it's not showing the C driver ID just go to the query oh needs to be public okay perfect so now that I have access to my driver ID so in case the driver is null I'm gonna return null else what I'm doing I'm doing all of this and I'm gonna be returning the result let us optimize it so instead of having this I can just return remove this and perfect so here basically what we have is we're getting the driver ID from the database if it is not really turning now else we're just returning the map function perfect so now how can I use that pretty straightforward I'm gonna need to specify my query equally new get driver query and we need to pass the driver ID because if we take a look at it as expecting a driver ID and again VAR resolved equal await underscore mediator dot send and here I'm going to be sending my query and I'm gonna say if result equal equal null I'm gonna return a not found else I'm returning the result I got this I can yep something like this so now let's try this if I go back to my web browser and let's get driver by ID so first of all I'm gonna get the IDS of the driver let me remove this Breaking Point perfect we got Lewis's ID let's take that and if I go here to get the refer by ID try it out description and you can see here we got the driver ID perfect and we're gonna put a Breaking Point again inside my driver Handler just to make sure it's actually being picked up execute and we can see it's actually directly being picked up and the ID is being passed correctly okay perfect so now that we have handled the two query stuff which is going to be the reading from the database now let's see how we can actually implement the command which is going to be either creating updating or deleting and as you can see here this separation of concern that we currently have is really powerful because all of the logic is being shifted out after the controller and the controller if we take a look at it is actually becoming pretty simple all we're doing is specifying for every single one of them is the actual query and the mediator is taking response responsibility to execute the rest of the logic which is pretty cool so now what we're going to be doing is we're going to check the post and how we can actually convert this into the mediated pattern so first of all I'm going to stop my application so inside my look directly I'm going to create a directory I'm going to call it commands and inside this commands similar to what we have for the queries I'm gonna create a new class on this class I'm gonna call it create driver info request because we want to add the driver so basically what we're doing right now is we're gonna convert the post by adding a driver into a command and again similar that we have done before I need to specify it's going to be I request type and I need to specify the return type so this one here the return time it will not have any but whatever what actually we are expecting here is the uh sorry the return type here is going to be the result which is going to be of type get driver response so let's do this here let's update it so here I'm gonna put get driver response and then something else we need to take into consideration that here we are not taking a simple query string what we're doing is we're actually having a an object that you want to send and this is going to be pretty safe forward similar to the good so what we want to do here is we want to make it a public let's copy this request and I'm gonna call it request just to drive a request just to make it simple thank you and it's gonna be good let's fix this reference and here I'm just going to specify my Constructor and I'm gonna tell it to initialize it through the Constructor okay perfect so now similar that we have done the previously for my get driver with not this one sorry with the query what specified the query and we initialize it similarly we have done here for the command we specified this object that we have and we have initializes so again for this what I want to do I want to now add the Handler for it and I'm gonna call it this get driver and for Handler again similar that we have done it previously I'm gonna inherit the I request Handler it's going to ask me what is the request type I'm gonna put the create driver and for requests and I'm gonna specify the return type it's kind of similarly get driver response again let's fix this it's going to ask me to implement the handle method perfect I'm gonna make this a sync again similar what we have done here I'm just going to copy these just to make it easier for me copy and it's called the driver and force put them here update the Constructor name and let's import them and now let's go back to my driver's controller let me take all of this logic that currently exists and let me put it inside my drive and handle let's remove this and here I'm going to update this to driver and here it's gonna be instead of drivers can be request dot driver request and what I want to do here is once I map it first of all from the driver request dto to the database entity I want to now revert it back so we can do the similar thing to what we have done here so let's take this I'm gonna put four results equal actually we're gonna put for driver result equal and instead of driver here we're just going to have I'm gonna call this driver set of results so we'll make it more consistent and this can be resolved again and what we need to do is we need to return it so there is no benefit of coming at result we're just gonna return it okay perfect so now that we have this in place now let's go to the driver's controllers and here it's going to be pretty straightforward I'm gonna put VAR command because we're doing a command now I'm gonna put the new create driver and for requests and here is expecting the driver again I have to create a far result for my query it's gonna be equal awaits underscore mediator dot sand and it's going to send the command so if we take a look at this one here we need to update this from ID to driver ID and that should be it so now if I run this and I go back to my web browser and Let me refresh this and let's try add the new driver so I'm gonna try to post a new driver try it out so first name put George Russell driver 63 year or no let's put 19.99 skip it like this execute and now we can see George has been added we got that to a one I got all drivers we're now actually able to get Drive Lewis and yours plus I'm not drastic anyways now we can see it's all working as it should be and basically within this we are able to see how we are able to have both the request and the query from within our API endpoint our API controllers but we have actually able to under a query handling command and how these two work together now what we're going to do is we're going to continue implementing the put and the delete to actually fall within the same pattern and then we're going to clean up our controller even more and make it much more simpler so let's see how we can do that so now let us update the update driver so first thing inside my command I'm going to create a new class and this I'm going to call it updated driver info request and here all I'm gonna do I'm gonna have the I request and I'm just gonna make sure the return type is Boolean because it's an update I'm not going to return anything and if we take a look at the driver's controller here we are expecting the updated driver request as a parameter so let's make it as a public and let's make it as a gut let's make this as a capital D here and let's fix this reference and then inside my Constructor I'm gonna just initialize this pretty straightforward perfect and let us inside my Handler here I'm gonna add the handle for it so I'm going to say update driver info Handler and it's going to be also pretty straightforward I'm gonna put the I request Handler it's gonna process the update driver and for request and it's going to turn a Boolean and now it's gonna complain that I did not implement the handle method we have done this already here and now all I'm gonna do is I'm gonna copy this implementation so I don't have to really copy it you type at all and I'm gonna update the Constructor name and fix this references perfect and now lastly if I go back to my controller I'm just gonna copy the logic that I currently have here and I'm gonna add it to the update Handler and I'm gonna first of all make sure that I return through and here instead of having a driver and I have to tell us a request to the driver and I'm gonna fix this reference perfect so now that my update driver in 400 is completed I can update this it's going to be a pretty straightforward similar that we have done with the create so I need to create a command for command equal new update driver request it's gonna request a driver as a parameter update driver info request yeah and for requests perfect and then I have my result equal await underscore mediator dot send and I'm going to send the command that I have and I'm going to say if result I mean if it's true I'm gonna return no content let's make it as a single line so I'm gonna put result no content or bad request so that's going to be for the update now let's do the same thing for the delete so for the delete we're taking a driver ID so let's create this command I'm gonna create the delete driver info request and basically here it's going to be similar request and it's going to turn a Boolean because it is expect an ID driver ID so let's take this and let's take it to the delete and let's make it public and let's make it as I got let's update this as capital D oops and what I want to do here as well is I want to initialize it perfect now that this is in place now all I need to do is go to my Handler create a handle for it and this is going to be straightforward so I'm gonna put a delete driver info Handler perfect again pretty straightforward it's going to be of type I request Handler it's gonna take the update driver information request Napoleon it's gonna complain why didn't I implement the handle I'm gonna make it as a sink copy these put them here fix the Constructor fix the unit of work perfect and then once I have done that what I can do is I need to go back to my driver's controller let's take all of that inside my delete I'm gonna put it here so this is gonna be request.driver ID update oops so this is wrong it's not the update it's the delete driver info request and this is going to be the oops the delete the driver M4 request so here all we're gonna have is a driver ID and if it's empty I'm gonna return false and here we're gonna have to put the request to driver ID and if everything goes into as planned I'm gonna put the return through and then inside my controller I need to update it so it's going to be pretty straightforward but command equal new delete driver info request we're gonna pass the driver ID and lastly we're gonna put far result equal await underscore mediator dot send request and we're gonna send the command and we're gonna say similar to this one just just copy it perfect and as you can see here that all of the dependencies that we were relying on before is gone our controller is much more simpler so right now if I update my base controller because we currently need it in the other one I'm not gonna remove them but in fact I don't really need the unit of work of eye or eye mapper inside of here before at all so what I can do as well to make it easier I'm just gonna take my initializations here and I'm gonna put it inside my base I'm gonna fix this reference and I'm gonna implement this here and inside my achievements I'm gonna do the same thing I'm just gonna implement it so I can just take it as it is from here and I'm gonna put it inside my achievements and let's fix this reference and I'm gonna make this here as a mediator so here as well it's expecting us to update it so let's do that and we don't need to initialize this here now let's see inside my base controller I need to make it as protected and that should be it so now if I run everything so let's run this if I go back to my web browser as we can see here that let's try with the gut all execute perfect and let's try to do the gut for a single driver so let's take the ID for George we are able to get it perfect now if I do the delete let's see if that will work the gun driver ID we got a 204 no content now if I got all drivers again I should only see a Lewis perfect okay so now that we have implemented the secure as pattern inside our application we are actually able to see how everything fits together we were able to see how we can actually separate all of the logic from inside our controller into a different commands and queries and handlers we're able to see how mediator was able to facilitate this for us to have a proper separation of concerns if we wanted to have a full uh full different query string for our get request if you're interested in implementing this please let me know in the comments down below and we'll make sure to have a video to cover this but in general we were able to see how mediated player Cruiser role here and basically to have this separation of concerns and how we were able to implement the cqrs pattern in order for us to have a better testability usability of all of our API if you like this video please like share and subscribe if you really have the channel as well if you'd like to support me please consider supporting me on patreon or by with us and have a great day and thank you very much for watching any questions that you might have please make sure you put them in the comments Down Below have a great day
Info
Channel: Mohamad Lawand
Views: 9,178
Rating: undefined out of 5
Keywords: .net, api, c#, dependency injection, entity framework c#, entity framework, asp.net core tutorial, .net core, asp.net core, web api, dotnet core web api, dotnet core, dotnet performance, dotnet configuration, how to code, dot net, sqlite, repository pattern c# web api, dotnet sqlite, dotnet cqrs, cqrs event sourcing, dotnet mediatr, dotnet mediator pattern, clean architecture, dotnet mediatr cqrs, command query responsibility segregation
Id: sUjNZAYTZwI
Channel Id: undefined
Length: 66min 47sec (4007 seconds)
Published: Thu Aug 31 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.