Repository Pattern | ASP.NET 6 REST API Following CLEAN ARCHITECTURE & DDD Tutorial | Part 3

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
this video is all about the repository pattern what is it when to use it and why is it so polarizing when it comes to storage in.net hi everyone i'm here i do have a quick disclaimer if you're new to the channel so i am a microsoft employee and these are microsoft technologies that we're talking about but i'm not talking on behalf of microsoft these are my personal opinions okay so with that out of the way let's continue okay so what is the repository pattern so microsoft says repositories are classes or components that encapsulate the logic required to access data sources so for microsoft definition all a repository is is an abstraction layer in which you hold all your data access logic so you just call the interface or whatever abstraction that you have and behind this abstraction system actual logic of querying the database maybe filtering and so on okay what does martin fowler say so martin feller has a similar but a bit different definition so basically he says that you have the data mapping layer and you have the domain layer and the repository abstracts away the data mapping and the data access logic okay so we'll look into that a bit later if you're not familiar with domain-driven design then don't worry this is intended also for complete beginners and domain-driven design so i will have sections here that i'm going to talk about specific terminologies from domain-driven design so if you don't understand it then don't worry by the end of this series you'll have a good understanding of these terms and what i'm saying now will make a bit more sense okay so you can revisit this if this doesn't make sense at the moment okay so let's let's look at an example so this video is part of my series of building a rest api completely from scratch following clean architecture and domain-driven design but it's also a standalone video so if you only want to learn about repositories and understand why this topic is so polarizing then you can watch this video without other context okay so what we have here is a dinner hosting system in which you have users they can create dinners so you can invite people to join your dinner and people can confirm whether or not they're coming to the dinner that you created okay it's sort of like airbnb where you have your home and you can turn it into a hotel so here you can take your home and turn it into a restaurant okay so let's look at an actual practical example of what this looks like so don't worry this looks a bit intimidating i'll break it down so what we have here is we have the create dinner command handler okay so this is using the cqrs design pattern and if you're not familiar with it then all this is is when a user wants to create a dinner in the system so this piece of code over here is invoked and what we have here is basically the user says okay i want to create this dinner so first we want to make sure that the user exists then we want to actually create the dinner and store it in the database okay so where does the repository pattern come into play here well basically we have these two repositories where we abstract away the logic of getting the user and adding the dinner to the database and for us it's just simply calling a class as if it's sitting in memory right so let's look at what this repository interface looks like let's look specifically at the dinner repository okay so let's say we have something like this where you have the identity repository and it has some methods for accessing the dinners that are stored behind the scenes now how is this implemented and are we actually storing the dinners or are we mapping it to a different object and then storing it in the database we don't know okay that's one of the beauties of this design pattern where you don't care about this right so you can have an in-memory list implementation where you basically have a list of dinners and they are manipulated to satisfy the interface but you can also be using entity framework and manipulate the db context in order to satisfy the interface okay so now that we have a better idea about what the repository pattern is and how it might be implemented let's try to understand why is this so polarizing because if you're looking at this and you're saying big whoop this is pretty simple right it's pretty intuitive and obvious why is this even called a pattern so let's dig into it and try to understand what's what's the story behind here okay so let's look at it from a few perspectives so first let's look at it from the perspective of clean architecture okay so so in this series this is the architecture of the final result of what we're going to be building over here we have the create dinner command handler that we looked at now and over here in the application layer we have our dinner repository and the user repository over here which follows one of the core concepts of clean architecture which is let's have the inner layers define interfaces and the outer layers will define the implementation which can be replaced with other implementations without the core logic needing to change okay so as we would expect over here in the infrastructure layer we have the actual implementation of those interfaces okay so if you're looking at this and you're saying great so it fits perfectly with clean architecture principles let's actually go back to the example where we saw we're using entity framework to implement the repository so if we look at this this is the data access solution that we're using what is this db context this is also an abstraction so what's sitting behind this tv context who knows it might be document db might be a relational db it might be an in memory we don't know okay and we don't care about what the implementation is because that's the beauty of entity framework that you can use different technologies and you have this layer of abstraction so why should we add another layer of abstraction on top of this layer of abstraction isn't this just redundant and now we need to test more stuff we have more logic that we need to maintain so this thing over here this is already an abstraction we can take this and just use it where we want to access it okay so that's a great case against it and one of the reasons that many projects don't use the repository pattern and just simply use the db context from entity firmware core because it's already an abstraction okay so let's look at it from the perspective of domain driven design now if you're not familiar with the main driven design this might not make a lot of sense so you can skip to where we're actually going to be implementing the repository pattern and if you want to get a sneak peek of what we're going to be talking about then you can follow along okay so from the perspective of domain driven design let's go back to the to the create dinner command handler right so if you're looking at two of these methods over here and you're saying this is actually much more readable than manipulating the db context over here and if you have the same logic repeated in multiple places in your system then it makes a lot of sense to encapsulate it and put it in one place not to repeat yourself multiple times so yes that makes sense but if we're looking at it from the perspective of domain driven design then the repositories work with the aggregates so that means that they store and load from the database the entire aggregate now over here in this example this is a very straightforward example where we basically have the c of crud on the aggregate so over here it's pretty intuitive we just add the aggregate and it makes sense over here let's look at an example where it doesn't really make sense okay so let's imagine that just like youtube has this big view where you can see your subscriber count you can see the live count so let's imagine that this application has become a big thing and there are big companies that are using it and they're really excited to be hitting a specific number of confirmed guests so what you might have if you're using the repository pattern over here and they might say okay let's get the dinner that we're talking about and let's get the count of the confirmed guests if you're thinking to yourself okay this is great then you might be forgetting that over here we're loading the entire dinner this entire logic can be encapsulated in a single query to the database where you do the query directly on the data and then you're not loading anything more than just an integer right so that's a good case now you might say okay i can fix this pretty easily here's the naive expert i'll just create in my repository a method let's get the count of the confirmed dinner guests i'll have this logic encapsulated behind my interface so over there i'll have it in a single sql query for example well here's a little spoiler this is going to be such a great feature that tomorrow you might want also the pending dinner guest and also the decline dinner test and then you'll see repositories which have so many methods that are just trying to optimize for the query to the database and it becomes this god file of accessing the dinner which can be just huge okay now there are ways to go around this so if you're familiar with the specifications pattern then we can create a specification and pass a specification and have that implemented that way and that's true i'm not going to be talking about the specification pattern in this video maybe in the future i'll make a specific specifications video that will dive deeper into specification how it can be used and implemented but that's not in the scope of this video so if you're watching this video because you're searching for whether or not you want to use the repository pattern in your application and you read multiple blogs and stack overflow discussions and you're not sure what you want to do then this is just a subset of the reasons from each side there are many many other reasons to why to use it or why not use it but there are some solutions so if like in our system you're using cqrs to separate your commands from your queries then you can for example use the repository pattern for the command side because in the command side we're manipulating data the manipulation of data is always on the aggregate so it makes sense that you'll load and store in the database entire aggregate and in the query side you won't use the repository pattern you'll just use the db context do whatever you wanted to join tables pull the exact data that you want to do and then you're not restricted by these rules of using only the aggregates okay so that's one solution that you might do but you might also say my system is not going to be so complex i prefer not having entity framework even referenced in my application or domain project so i want to put everything behind this interface it's easier for me to mock in unit tests then that's what i want to do and you know that your system is not too complicated and this file won't become a gut file then you might just use the repository pattern always and that's it in your application and that's completely fine okay so that's it about the repository pattern if you're a board and you're looking for something to do then i highly encourage you to look at these discussions it's just fascinating how passionate people are on either using it or not using it now in the system that we're going to be building we will be using the repository pattern and that's because i want us to get familiar with it and see if it's right for your applications so this project is only for educational purposes i don't want you to take the repository pattern because we're using it here and use it in your applications you need to make sure it makes sense for your scenario okay so now that we have all this out of the way let's go ahead and implement the repository pattern in our application so what we have is the register and login request which arrive to the authentication controller and from there to the authentication service in the application layer and currently what we're doing we're returning a jwt token back to the user and the user isn't persisted it's not validated that the user actually exists when he tries to log in nothing like that that's what we're going to be doing today so we're going to be creating the i user repository interface which will be implemented over here in the infrastructure layer which will currently be implemented just as a static list of users but in the final result we're going to be using entity framework so stay tuned if this sounds intriguing okay and also we're going to be creating the an intermediate implementation of the user entity in the domain layer this will change multiple times in the upcoming videos so this is just implementation that we're going to be using for now so when we get to that stage then we'll talk about what our application is all about how do we want to model our entities what's the relationship between them and so on there's many many topics to talk about so just for now this is the implementation that we're going to be using so let's go ahead and implement the i user repository interface and complete the register and the login flow which allow users to actually register and log in okay so let's go ahead and do it so hoop is big after all okay so the first thing i want to do is actually go over here in docs and we'll always keep here the domain models as their current state evolves so let's have here domain models and over here let me paste the definition that we looked at before let's open it in the markdown preview enhanced extension right so this is what we looked at before and i just put here a note this is a disclaimer of course this will change in the future this is just again an intermediate implementation okay so let's go ahead and model this so in our domain let's create a new folder it's called entities and over here let's create our user a yes actually this looks good let's just fix the indentation here let's create here the last name the email and the password okay now let's say that if we don't specify the id then this has a random new guide and because we have nullable reference types enabled then let's just tell the compiler this ain't going to be null okay so let's go ahead ahead and over here in the interfaces let's create a new folder let's call it persistence and in here let's create the i user repository interface okay now again we have two things that we want to check when doing the login and the registration one of them is fetching the user by the email address and the other one is adding the new user okay so let's add these methods so i use a repository and over here let's have yes add and also let's have here um get user by email let's say okay and basically what we have here is we specify the email and then we might get a user and we might not get a user if it doesn't exist and over here we pass the user and to add it to the storage okay now again we don't care about implementation we're in the application layer we're just defining the interface let's go to the authentication service and inject it over here so let's say private read-only i use the repository user repository let's add it to the constructor and here let's have our actual logic okay so the first thing we want to do is validate the user doesn't exist right after we've validated the user doesn't exist then we can create a new user generate a unique id and persist yes the user to the database then we want to create the jwt token and return to okay so let's start so if now you want to check in the user repository if yes let's say here is not null then let's just say for now let's just throw an exception okay so throw new exception user with given email already exists okay next let's create the user so let's save our user equals new user and here yes let's give it the values right seems about right let's wrap it it's more readable then let's persist it to the database yes and now we can create the jwt token over here we no longer need to have this new guide over here because it was generated as part of the creation of the user let's put this over here and that's it okay for a login what we want to do is first of all we want to make sure that the user does exist right if it does exist great then let's make sure yes the password is correct and after we make sure that password is correct then we want to create the jwt token and return to the user all right so if and here we want to check if the user so here we want to say if the user doesn't exist then and again for now let's just throw an exception yes okay now now in actuality this is a bit dangerous to return because this might appear to the client that's making the request and then if someone is just guessing emails then over here you can keep guessing until he gets the correct email and then you can go ahead and start getting passwords so again this is just an intermediate implementation and for us to be able to test it now and see that it works okay next we want to say okay if yes the user isn't correct then okay invalid password if not let's create the token let's say bar token equals yes generate token and over here let's return the actual values so it's going to be user id this is going to be user.firstname this is going to be user.lastname email and token great so we have our application logic ready now let's go ahead and implement the user repository in the infrastructure layer okay so let's create over here a new folder it's called persistence and let's create here the user repository implementation and this will this will implement the interface that we just defined so public class user repository yes capital u i user repository let's implement the interface and for now let's just have a list it's not thread safe it's not the actual implementation again this is just for now okay so let's go ahead and say private read-only let's say list of user users equals new yes adding will simply be users.nbc and getuser by email it will be users dot single or default where the user dot singular default where yes the user's email is the given email let's return this and that's it for now let's go ahead and let's go ahead and configure this in the dependency injection ioc container so let's say services add now one thing about this so we define this as scoped then it will create a new list of users for every request so let's make this static and let's say here at scoped i use a repository again from the application layer and the user repository from the infrastructure layer okay this seems about right let's build the project and make sure that it works great always fun to see now let's run the project so let's run the api project let's make a register request if you haven't watched the first two parts of the series then this might seem a bit weird to you but all this is the visual studio code extension which allows you to send http requests inside visual studio and we have here the response it looks about right now let's make sure that when we log in we actually get our response so just a reminder if we look at our api definition then when we do log in then we pass only the email and the password but the response contains also the first name the last name and the email so if we succeeded in persisting the user in the in-memory database then we should get these values back so let's go ahead and make this request and perfect we get the values this means that everything works as we expect last thing i want to do is to refactor this a bit so let's close everything so it's a bit more organized over here in the authentication result so we're returning all these values individually this is actually just the user right so we can say okay let's just return here the user and in the service instead of returning it like this you can say here user same goes over here and then in the authentication controller then instead of accessing them individually we'll access them through the user both here and here and let's close this again just so it's more organized over here in the jwt token generator again we're getting here the values individually ideally you'd want to guess here the user and then we can retrieve whatever values that we want to add a scopes to the token so i just say here also user user let's go to the implementation and update this as well so all this we can replace with user user and retrieve the values via this object and here this is user dot capital f user dot capital l that should be enough so that's it for here let's go to the authentication service and update this as well so over here let's just pass the user both here and here let's run this service again let's make sure that this still works okay so it still seems to work let's make the register request and we have our response let's make the login request and we get these values which means it was persisted in our in-memory database okay now of course we don't have any error handling so if we try to register the same user again then an exception is thrown right and with the message that we defined and same goes if we try to make a login request with an email of someone that doesn't exist so we'll get here the user with given email does not exist and if we use an email that does exist but we butcher the password then we get this error over here so the future videos we'll look into error handling it's not part of this video so that's it i really hope that you like this video please let me know in the comments if you use the repository pattern don't use the repository pattern please feel free to educate me on any topic if you have any tips visual studio code csharp.net i'd love to hear from you and learn from you as well okay so that's it and see you in the next one
Info
Channel: Amichai Mantinband
Views: 71,340
Rating: undefined out of 5
Keywords: dotnet, c#, clean architecture, domain driven design, DDD, jwt, jwt token, .net, .net 6, rest api, Repository, Design Pattern
Id: ZwQf_JQUUCQ
Channel Id: undefined
Length: 22min 46sec (1366 seconds)
Published: Mon Jun 13 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.