ASP.NET Core - Clean Architecture - Full Course

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] foreign [Music] I'm Trevor Williams and it is my pleasure to welcome you to this course asb.net core clean architecture now in this free preview of the course you're going to learn a number of things you're going to learn how to implement the cqrs pattern you're going to learn about fluent validation you're going to learn about the repository and unit of work patterns and while doing all of this you'll get exposure to popular libraries such as Auto mapper Entity framework core mediator and we learn how to use in swag and in swag Studio to generate API client code and the client app is going to be an MVC based application so when I tell you that this free previous chock full of information it is however in the full version of this course you get more you get one more updated tooling more updated techniques and applications of these techniques and I do encourage you to go ahead and use the link in the description once again to check out the full course but for now enjoy this free preview and I'll see you at the end welcome back in our first practical lesson we're going to be setting up our solution so I have Visual Studio 2019 open if you don't have Visual Studio 2019 already installed you can easily go to visual studio.microsoft.com vs and download the Community Edition the Community Edition is free for educational and individual usage of course if you're good if you're a commercial then you're expected to get the professional or the Enterprise version once you have downloaded it you will be presented with an installer and what you really need from this installer at the very least is the asp.net and web development workload so by ticking it you're indicating that you want that workload you'll see other workloads available you can tick them if you wish of course the more you take is the more you'll need to download but for this course you really just need this one which will give you all of the tools needed for any asp.net web application as well as dot net five so once you've completed that setup or if you're already had it installed and you can continue along with me and we will go to create a new project so what we're going to do is create a blank solution which I have in my recent project templates but if you don't have that you can always search for blank solution in this area and then you get an empty solution containing no project so that's what we want and we're going to be calling this project HR dot leave management now there's no particular reason for me to call it this it's a leave management application it's being built for the HR department if it was being built for a company then you probably would want to say company dot the type of system so if you want you can go ahead and use my name or change that name accordingly but once you have put in a name that is valid then you can go ahead and click create now we won't be writing any code in this lesson but we will be putting out that project structure as we need it for the version of this course or this whole project so the first thing I'm going to do is add a folder and I'm going to call this one SRC shortforce source and another folder that we're going to call tests now under SRC I'm going to add a few more folders I'm going to call this one the API because that's what will interact with our client application I'm going to have another one called core one more called infra structure and finally one for the UI so that's all we're doing for this lesson we're just setting up the project structure so when we come back we'll start creating the different projects that will go in each of these sections all right guys welcome back in this lesson we'll be creating our domain projects so our domain projects will go underneath our core folder inside of our application we can go ahead and add a new project and what we're going to be doing is adding it as a class Library C sharp class library of type.net standard all right so it's not standard allows code sharing across many different platforms so we'll just use that one for all of our class libraries and we're calling it hr.leave management.domain since it will be used to store all of our domain objects or entity classes that get translated into our database tables so I can go ahead and hit next and the target framework here is.net standard 2.1 go ahead and hit create now once that is done we get our default class one which we can actually delete and then start populating with our classes so going back to our project on GitHub just quickly you'll see that the domain classes were held inside of the project in a folder called Data so our domain classes included leave allocation leave request and leave type if you want you can go ahead and retrieve them but I will be going through them anyway so if you just take a quick look at these classes you'll see that each one had an ID and we also had a bunch of properties in each one some properties that kind of repeated would include date created between the leave type and the leave allocation record and then it's inconsistent because leave management or sorry leave request doesn't really have that so we'll be fixing some of those inconsistencies as well as reducing the repetitions between them so I'm going to start off with leaf type so I'm just going to go to the project click add new class we're calling it leaf type and I'll make this public from now now inside leave type what we're going to have are fields for ID name default days and date created now I did specify that date I feel like date created is really an audit field and this needs to be found across the different classes so I'm just going to go ahead and add all the entity classes so you can pause replicate that for the leave request we are going to have an ID field a start date and end date the leave type the date requested request comments date action and approved in the form of a knowledgeable Boolean and canceled in the form of a Boolean so you can go ahead and replicate that now if you're comparing this with what is on the GitHub reference there are some Fields missing which were not quite ready for just yet in the form of the employee which would be some user related data we don't have that yet so we're not prioritizing that we can introduce that later on through some migrations now the third entity that we're going to add is leave allocation and for this one we're going to have the ID the number of days the date created leave type leaf type ID and period once again I've kind of omitted the employee related fields as well as those data annotations now in terms of repeating Fields versus the need to have consistency with at least the fees that need to be repeated namely the date created usually when we're talking about auditing we want to have date created who created it the modified data and who last modified it right so that way we can keep track of everything happening across it as a matter of fact we would actually solve some of the things with the whole referencing to the employee and so on with these auditing Fields so what I'm going to do is introduce another folder in this domain project and I'm going to call this folder common and then inside of common I will have a class that I'm going to call Base domain entity now what does my base domain entity have well it's going to have all of the base fields that I know every class or every domain entity is going to need I'm going to make this an abstract class so that it cannot be instantiated on its own however it can be inherited by everyone else so this is going to be ID because every table is going to need an ID I'm also going to have four other fields one for the date created then created by then a date time for the last modified date and another one for the last modified buy now with this base domain entity I can now let everybody else inherit so I can just go back to my actual entity class and let it inherit from the base domain entity including any missing references using control Dot and there you see that these fields that I have inside leave allocation that have the same names as the ones in base domain entity are lighting up so that means I don't need to repeat them all right that looks a little cleaner all right so I'm going to leave request and I do the same go ahead and inherit include the missing references and then all of a sudden I don't need to say ID over here either and then in leaf type I do just the same thing including missing references and then I can remove all the repeated fields so our base domain entity gives us access to certain fields that are expected to repeat across every entity as we all want them to have these all right so with all of those changes made let's go ahead and hit Ctrl shift and B to do a build and we have a successful build so we can move on to the next task hey guys welcome back in this lesson we'll be discussing our application core layer now the purpose of this layer is to sit in between our application application being whatever would be wanting to access the database and the database so in this layer we'll be defining all of those access parameters to mediate between the calling application and the database itself so this project will sit directly inside of our core folder so let's go ahead and add a new class Library and I'm going to be calling this one HR dot leavemanagement.application go ahead and add it once again we're using.net standard 2.1 and go ahead and create so now that we have our class Library I'm going to remove that default class and then I'm going to add two new folders to this project so the first one is going to be persistence and then inside persistence we're going to have another folder called contracts so inside of contracts we're going to be defining all of the abstractions for our repositories now the jury is out on what are the best ways to implement this once again there are a few opinions it's a proposed architecture and there are a few opinions and some opinions get implemented based on context but I'm just going to explain why we're using the repository pattern so one in the in keeping with the dry principles we don't want to repeat queries too often also you might have specialized operations that you need to carry out on any one of these domain objects so when you define a repository per domain object then you can have custom code or customized methods inside of that repository for these right now we're not implementing the repository though we're just defining the contract so the contract here the first one will be an interface and I'm going to call it I generic repository uh I said class here I'm making a class but even if you use class you know you can just make it a public interface now we're going to tell this interface that it will be implemented relatively to a class called T so we're just using oper generics as in keeping with the name generic repository so that any one of our domain objects can be used to access database related functionality through this interface so some of the methods that we're going to implement in this interface include a get method so we have task T get and then we can just go ahead and include any missing libraries we're also going to have task get all but this one is returning and I read only list now if it's the first time you're seeing this data type usually and personally I usually use a list or an iOS or one of those more popular collection data types I read on the list its benefit is that it keeps it in a read-only state so it cannot get modified once it has been pulled from the database and sent over so less tracking and less database related operations after the data pulls so we'll look at it in a few but that's the data type I'm using once again you could easily have used any other collection type of type T could have been at least could have been Eye collection um but then I read on the list is serving the purpose I wanted to uh we're going to have the task to add on we're also going to have tasks to update and delete so you see the the generic repository is not only generic for T but it's also generic in terms of the functionality provides which are the basic and standard crude functions there's also a naming convention where people would put on the word async because you can see we're all using tasks here so sometimes you would see them Define it as get async so it's obvious that this is going to be an async function so you could follow that name convention if you want I am not going to so we can move forward now the thing with the generic repository is that once again it's just the generic crude functions that every single database table May ever need to perform however when you have something specific to a leave allocation operation or a leave request operation you can build this out and the code might get messy if you try to build it out in certain parts of the application so what we're going to do is Implement specific repositories based on our generic repository or to extend our generic functionality but specific to either or any one of our domain objects so I'm just going to go back to contracts and I'm going to add a new item in the form of a class once again but it's really going to be an interface and I'm going to call it I leave request repository once that's created we make it into a public interface and then I let it know that it is extending a generic repository and it is specific to our class type of leave request all right so leave request is our domain remember that this was relative to type T so this is the T that we're passing in but then you'll see here that it doesn't know anything about it says that we need to add reference to HR management.domain so you can click that um in all honesty that hasn't quite worked for me when I use it there so I just go over to dependencies let me do that again sorry dependencies add project reference and then I just tick the reference to The Domain objects click OK and then I can now include that using statement here all right so inside of this repository then if we have specialized functions relative to only leave requests then we can Define them here without modding up the generic repository and without the other specific repositories needing to see it you know we want to keep everything kind of contained in one place so following this example I'm just going to go ahead and Define the other repositories I leave allocation and I leave type repositories so once that activity is done we end up with two other interfaces so we have our generic repository we have our I leave allocation repository which is implementing or inheriting rather the eye generic repository uh relative to leave allocation and then we have that again for leaf type with I leave type repository extending I generic relative to leaf type so that's really it for this lesson we're just setting up the contracts and those contracts are in the forms of these interfaces because remember that we don't want to directly interact with the code when we're calling but we are going to be dealing with the abstractions that way we can make code changes without disrupting too much of the code from the client-side application hey guys welcome back in this lesson we're going to be setting up Auto mapper now if you don't know what automaker is that's no problem it is really just a library that helps us to convert between one data type to another simple right so the context behind why it will be useful is that we'll be implementing the mediator pattern in a following video but that mediator pattern will be acting as a messaging mechanism between what is coming from the client and What needs to go to the database it is generally speaking bad practice to interact directly with the domain objects at least before we get to the repository so that means we shouldn't be allowing any calling application any client any application that is talking to our application core to be sending us directly or direct objects off the domain object type instead we create abstraction so we create data transfer objects or view models you can call them either one but they're really just classes that kind of look like the domain object but have restrictions based on the operation so an edit operation has different requirements from maybe a create operation so you would present the ID in one and the ID wouldn't be presented in the other once again all you have are abstractions for that you can get granulo or you can keep it General that's up to you the point is auto mapper will help with the conversion between the abstracted or the client friendly version of this object and the database friendly version of this object this is going to promote loose coupling throughout our application so with all that said uh the setup is not going to be very complicated for this one what I'm going to do inside of this application project is create a new folder and we're just going to call it profiles now a profile is basically just a configuration file for Autumn but you know that it is allowed to convert between one data type and another so I'm going to create a new class inside of this folder and I'm going to call it mapping profile and then I need to introduce and I'm going to make this public of course but I need to go to nuget and get our Auto mapper Library so I'm just going to right click manage new get library and then I'm going to search for auto mapper and the one I'm interested in is automaper.extensions for dependency injection that will come with all the dependencies including the base Auto mapper library and anything else needed so it can be used for dependency injection accordingly so I'm just going to go ahead and install that one of course accepting and allowing any prompts that come up and once that is installed inside of mapping profile I'm going to let it inherit from a class called profile and this class is found in the auto mapper Library all right so we have the profile set up that's good now the next thing that I'm going to Define would be my data transfer object so I've created a new folder inside of this application project and in this folder I have a few files one I have a common file or folder rather with a common file called base detail so similar to how when we were sitting on board domain objects we had a common and then we're at the base domain entity which had some base uh properties that should be across all of these domain objects it's the same way that I've just made base detail and the common property would be ID I don't need the date created and so on with the dtos that's just for auditing so that's in the background so what I really need shared across them all would be the ID and then inside of each of these which I haven't done as yet I will then have other properties that I know each of them need to have in order to successfully taxi useful information for me so this part is as easy as going to leave type and taking the properties that you know you'd want to allow your application or your users to be able to interact with so with leave requests these are all required properties some just literally as you see I'm just copying and pasting the hard part really was just defining the base detail and letting the inheritance put on that IDs and note details talk to details so you see here that leaf type is being retained you see leaf type is being retained you don't let the dto know about the domain right so this should be leaf type dto and this should also be leaf type detail and as a rule of thumb details speak to dtos is what will allow the conversion between one or the dto and the domain so instead of our mapping profile we're going to have a Constructor so you can just say ctor tab tab that generates our Constructor and then I'm going to have a line that says create map and create map is saying between a source and a destination so t-source would be let's just say leave request would be my source that's the domain object and leave request dto and that would be my data transfer object all right so we're creating a mapping configuration between leave request leave request dto and I just close with the parentheses and then I can extend this again and tell it that it can reverse map now Auto mapper is very powerful I have seen applications where people put some amount of business logic in automapper itself when working with complex and probably cross domain applications you probably want a domain or a BTO to be able to convert to a domain object on one side and the domain object on another so you could actually have multiple mapping configurations from one object to another you could also create custom converters to say this member goes directly into that matching member on the other side there are a number of things you can do with that that could be a whole course by itself but today we'll just keep it simple with our simple configuration requirements so we have leave location and then we have the matching detail and then finally we have leaf type now I want to point something out I actually alluded to it earlier but I want to mention it again there are times when you want to get a bit more granular or have dtos specific to a certain purpose so let's look at leave request the leave request detail has quite a few fields the purpose of a dto is to limit the number of fields to reduce over posting and or under posting or providing too much information to the user so what I'm trying to say is that in the event that you want to see a leave request then all of this data becomes relevant right but then in the event that you really just need to list it or show a listing of all the leave requests you probably don't need all this data that the user doesn't need to see all this data when they're requesting just the list they don't they definitely won't need to see the comments at that point they probably don't need to see that date action the approved or canceled when they are listing so in that case what tends to happen is that you probably want to break it out a bit more so sometimes you would end up with a folder inside of the details and that folder would be specific to maybe leave request and then inside leave request you have all of the details that defer right so you have leave request detail that's fine this one would be for the details but but maybe I have another detail specific to listing so you would have leave request list detail which yes it would have the base dto also but then it has far fewer properties in it so you probably just need leave type the date it was requested and if it has been approved or not right so once again this is all relative to whatever you think you need to provide but I'm just saying that in this situation you probably don't want to put every single thing in one detail and then always use this dto every time a request is made no matter how minuscule the request is or how little data they really need in that situation so that is the purpose of the dto so actually with those changes I know I broke some code let's well firstly let me update the namespace on this leave request detail so that it knows it's new location and then I have to update my mapping to no no that it has leave request list detail to worry about also so I'll just go ahead and update those and then let's do a build all right build those successful the last thing that we're going to do here is set up an eye service collection registration method so the purpose of this is well in keeping with dependency injection we want to be able to have all of our components all of our injectable components defined inside of the application Level but then any client application can go ahead and just call the method and have it registered inside itself so when we get there you'll see it but I'll just do this right now so this would be application Services registration so this is going to be a public static class and it's going to have a method that I'm going to call public static void configure application Services which takes a parameter of iservice collection so we can just go ahead and include any missing references and then inside of this we get to say Services dot add Auto mapper all right so if you're familiar with.net core and dependency injection you'd see that this is just a service collection that you would have seen in the startup file for any.net core application so the thing is that we're abstracting it to just this project so that when we have that.net core application we can just call this method and then it would go ahead and register every service that is defined inside of that method so we are adding Auto mapper and then I'm going to say assembly dot get executing assembly go ahead and add any missing references now if you're familiar with auto mapper you've worked with it before but you're not necessarily familiar with this you'll probably be more familiar with us saying something like type off and then we would find the mapping profile and then that would allow us to register this profile as the Autumn upper configuration in general the thing with the this is that for every mapping profile you have you would probably have to repeat this line and you based on the size of your application you may end up with multiple mapping profiles because I've seen where you can have mapping profiles per domain object and per well per dto domain object appearing based on the number of databases or domains that are present right same or even at an application Level One application or one client application may have different mapping requirements from another so you keep them separate so my point is that by saying assembly dot get executing assembly it will just Traverse for every mapping profile that has that inheritance pretty much and it will just work all right no easier way to see it so that is how we're registering our automaper in our dependency injection and that is US setting up Auto mapper in general so if we build and it is successful then we come back next and continue our application setup welcome back guys in this lesson we'll be implementing two patterns that help us to promote loose coupling through our application they are the mediator pattern and the cqrs pattern now the mediator pattern is seen as a behavioral pattern because it allows you to Define exactly how a set of objects interact with each other in more simple terms you make a request and you get a result based on your request every time you make this request you can expect this kind of result that is a kind of consistency that it helps you to implement it also helps you to abstract all of that logic based Associated sorry with that request from the calling application now the cqrs pattern and cqrs is short for command and query responsibility segregation it helps you to separate the read and write operations from any data store so in the name command and query command is anything that is going to augment the data any write operation any update operation and a query is me reading the data so you can always know that when you're doing something that's going to augment the data it's a command if you're reading data it's a query so let us get started we're going to go over to new get firstly and we're going to grab the mediator package which is interestingly enough authored by the same person who gave us Auto mapper and that is Jimmy Bogart so we're going to go ahead and install that and once that is done we're going to come back to our configure application Services method and we're going to make a few changes here so some of those were oversights on my part initially and I apologize so we're changing this from a void to an ice service collection that's one and then we're adding these two lines we're seeing Services dot add mediator assembly dot get executing assembly just let the auto mapper and we're returning services so for the ad mediator I'm just going to go ahead and include the missing references and there we go so that is what this Service registration or eye service collection method should look like now that we've done that part let's just backtrack and regather our thoughts and think about what we need to do we need to implement the cqrs pattern so the cqrs pattern once again separates commands from queries in other words we need as folder for the commands we need a folder for our queries either command or query will be handled by what we call a handlers so when you make a request it gets handled and the Handler is going to be either a command to augment the data or something to return data so you see that there are quite a few moving Parts at this point and this is why this can have so many opinions on how it gets implemented so once again I'm not prescribing an implementation method or folder structure but I'm just helping you to visualize it you may change it based on your needs but this is how we're going to approach it so I'm going to create a new folder inside of our application project I'm calling it features and then inside of the features we're going to have folders per domain type and the reason I say domain type is that the feature of the application is relative to what you're going to be doing against a domain object against the database right so I'm going to be doing it in chunks based on the table or table specific features that the application offers so let's start off with a simple one like leave type so instead inside of features we're going to have leave type I'm going to just paralyze this Leaf types and then inside of the leaf types folder I'm going to have a few other folders I'm going to have requests handlers then inside handlers I'm going to have commands and queries and that is the folder structure that I will be working with now like I said opinions differ on how the folder structure could look some implementations would actually have the top level for the domain the feature name and then they would have commands and queries and then inside of commands or queries there is where they would have all of the requests or have a folder sorry per query let's say inside query they would have a folder for the specific query say get leave type list that would be the query so inside of that you have the get leaf type request get leaf type request Handler and the dto specific to it so once again there are many ways that you may see this implemented but the concepts remain the same you just want to make sure that you can identify your commands differently from your queries and you know where your requests are and requests are relative to handlers so now that we have the folder structure in place let us get started with some coding so inside the request the first request I want is to get the leaf type list so naming convention wise you always want to imply what the request is for or what kind of request in the name right so get leave type list and I'm going to specify request all right so get leave type list request and this is a public class and it is going to inherit from irequest so this this courtesy of mediator and it is going to then ask what should this request expect in return so when I request using this data type what should I be getting back well you should be getting back a list leave type ETO because once again data transfer objects are what will come in and what will go out never the domain objects so that is our request now there might be times when you may have parameters they can put in the request and so on but this is a very simple one I'm not going to get into any of those complications just yet so that is our first request next up we need something to handle this kind of request now this is a get request which makes it a query so inside of the Handler section I'm going to go to the queries folder and I'm going to say add a new class and I'm going to call this one the request Handler so that is my naming convention so I have a request by name and then I just append Handler so go ahead and add that one as a public class which is going to inherit I request Handler once again courtesy of mediator and then I request Handler says okay what request am I dealing with so its request is the get leaf type list request all right so that that's the naming convention that I like to use and more than likely you see that naming convention a lot because then you can specifically tie a request to a Handler by that similar name one is the request one is the request Handler so you can go ahead and include any missing references so it says what request am I handling and what should I be expecting to return so the return type of the request should be the return type given here so it is expected to return leave type dto in the form well a list of leaf type detail all right so now that's done we still have a red line this red line is because we need to implement the interface so almost automatically we actually get a method here that says handle it gets the request as the parameter and then here is where we write all of the code to handle whenever this request comes in now before we start handling any requests here we have a few dependencies one we need to be able to talk to the database now we haven't implemented anything but we do have our persistence contracts so these are contracts that will actually talk to the database so we're still not directly interacting with the domain here at all right so I need to inject the missing references so using ctor tab tab I'm going to get a Constructor and then I'm going to inject an i leave type repository so I'm just going to go ahead and inject that me add any missing references and then having typed it in the Constructor I can now say create and assign a field all right there we go and I tend to use the underscore because I like to see the underscore so I know that this is definitely the private field in the class so that is my naming convention you don't necessarily have to as you see the auto generated code didn't give you an underscore so that's fine now another thing that I would want to inject is I mapper because I do need to do some mapping when I get the data from the database when this repository Returns the domain objects I need to convert them to details to send back so I need Auto mapper also so I'm mapper include missing references also go ahead and inject it or create and assign the field and there we go so we have everything injected and ready now to implement this Handler code what I'm going to do is run a query against the leaf type repository so I'm going to say VAR Leaf types is equal to a weight leave type repository dot get all now this is awaiting so that means this method needs to be asynchronous and then you'll see that the one error goes away at least and then what we need to return is the list of leaf type ETO so I'm going to say return mapper dot map and then this is where this comes in handy leave interleave type dto but it's a list of leaf type DT or rather and what I will be mapping into that will be the list of domain objects coming from the query and there you go everybody's happy so I have a request saying I want the leaf type list then we have the Handler saying okay I can handle this request for you so that is what we mean by defining application Behavior or defining how objects relate to each other this request will always relate to this Hunter I believe if you try to have multiple handlers for the same request you would actually run into runtime errors because of some ambiguity so that is how we get to clearly Define that when you made this request you can always expect this Behavior now let's look at another request and it's still going to be a query but this time I want a specific leaf type so I was saying that you may see requests or you may end up having Fields or properties inside of a request that will be needed in order to handle the specific operation so what if we wanted to get a leave type not the whole list but leave type detail so I'm going to create another request and this one is going to be get leave type detail request once again remember to make it public now in this situation I'm going to add a property and I'm going to say ID so we're getting the detail which means we want a specific record and the best way to specify a record is by sending over the ID so we need a Handler for this request so I'm going to add that Handler another class for get leave type detail request Handler there we go make it public now one step I missed inside of the request I needed to inherit from I request and it is only expecting a leave type video one this time right so the requests detail go ahead and me add all missing references there we go so the Handler is now going to inherit from I request Handler and go ahead and add missing references it is going to be a handling requests for get leave type ETF request and it is expected to return a leave type ETO so once all of those missing references have gone in you can go ahead and implement the interface and then we start off with that now we're going to need basically the same injections that we had to use for the list so I'm just going to expedite that and copy and paste that code and just change the name of the Constructor and go ahead and add all missing references and once you have done all of that you can get started on the specific code so in this situation I would say VAR leave type is equal to and we awaits the method call to leave repository dot get and get is expecting an ID so I have the request object here inside of the parameter for the handle method so I can now say request Dot ID right once again we are waiting so this needs to be async but I'm just showing you that that is how you would go about using those fields in your query in your generic in your repository sorry so then when you have specific methods defined inside of leaf type repository then you can have more specific fields for your requests that are needed to handle those kinds of operations so once we get that the next thing we need to do is return the leave type detail object so I would say mapper.map into leave type dto and we are mapping leave type so once again all the details leave now one thing to note is that in handlers we have a clear separation between the commands and the queries but in requests there is no clear separation so when requests start getting created for the commands we have to rely on our eyes we have to open up tired so that we don't get confused as to which request is For What and I don't think that that is very efficient so I'm going to have commands inside of my requests and I'm also going to have queries so I know that whenever I want any requests surrounding queries I know exactly where to go and the same for commands so like I said they have differing folder structures some people once again would have just said leave types and then they would have had the commands and then inside of the commands they would have the different commands with all of the resources needed for that specific command the detail the Handler the request all in that subfolder so as you break this so you realize that you're going to need more files more folders because you want this that's a clear separation as much as possible once again how this is implemented is relative to the Creator so I'm just going to move my queries that I've created so far into that specific folder and of course I have to update that name space and once I do that I'm going to go ahead and update my handlers to know the new location of their corresponding requests so with all of that done I'm going to do a build and that build was successful and you see how it's all coming together so if you want you can go ahead and implement the other features we started with Leaf types you can at least implement the different the two read or the two query operations relative to leave allocation and relative to leave request welcome back guys we're continuing on the same vein of setting up our queries for our additional features so we already went through doing it for leaf types and the assignment was to do it for leave requests and leave allocations so I've already done that and I'll just be walking you through so if it is that you haven't completed it I'll go slowly enough and explain everything that I am doing so that you can replicate it and if not then we can just compare notes and feel free to let me know if you have done anything differently from how I have done it so the first one let's start with leave allocation so I have the queries and I have the well I have the handlers and the requests and I have the queries in either one now following the standard so far you'd see that our requests look fairly similar to what they look like for leaf types we have the get leave allocation detail request which takes the ID and I also have one for the list all right so in the queries I have a slight surprise for you I don't know if you did it this way but I'll walk you through exactly what has been done differently so of course we're including the correct the leave allocation repository rather as opposed to the leave type repository because we're dealing with leave allocations right now in terms of our handling you'd see that I have a method here that we did not go through in our in our repository setup I have get leave allocation with details now the purpose of me specifying this is that when we get the details of the leave allocation and if you need a reminder or leave allocation actually has a navigation property of leaf type which means if I want to show what leave has what number of days I have to show the name of that leaf I can't show the ID that's useless right or the client rather can't show the ID they would need some amount of details of the leave type on their side so when I say with details the purpose of that method is to do that include include that navigation property and everything so that by the time I get back that leave allocation I would have all of that logic done for me already and all I have to do is map and return so at this point I'm just going to pause and point out that you would see design patterns sometimes where they actually do all of that complex logic right here in the Handler so I've seen where they would actually directly connect to the context here in the Handler and then do all of those raw queries right here in the Handler and then massage it and then finally return what they need to return so that's one design pattern you might see another one is where we abstract away all of those logic and complex queries and you know business logic and then make methods for the repository now I'm not saying one is better than the other because either approach has its pros or cons in the in terms of making methods that specifically deal with a scenario like getting the leave allocation with the details in terms of that it could be good to put that in a repository method where you have a direct reference to where that logic or that kind of operation is happening because you may need to reuse that same kind of logic in multiple handlers so that would actually reduce the repetition of the same kinds of queries and same kinds of inclusions and everything I across multiple handlers if you just have it in one repository space the downside to repositories however is that because of how specific things can get yes we have the generic stuff but obviously this is not a generic command that every single feature or domain object may use the same way we have to have a specific method and then we're going to go probably end up doing a rabbit hole of having many specific methods in our repository so that is one of the downsides to the repository pattern now like I said if you do everything here in a Handler it would work but once again the downside to that is you might need to repeat that kind of operation across multiple handlers and then you end up repeating code in multiple places and then modification right become difficult in the long run so that is just the surprise app for you so if you take a look at our interface you'd see here that actually have both for the list and for the individual now the juries out on whether I need both the reason I included the one for the list of course is that in the list of the leave allocations I want to show the leave name and the day the leave name and the date leave type name and the day so I would need to include the details here and then if you're viewing one of them you would want to see the details also so I've just done that and I did the same thing and when you're working with a lot of us you need to navigate quickly so I'm just going to use this blue arrow up top here to synchronize to where this document is quickly and then in leave request you'd see that I have similar methods because in the leave request we need to know what kind of leave is being requested and if viewing the list you'd want to see this sleeve type was requested on this date Etc all right now in terms of our leave requests I have another slide surprise and I hope that you guys caught on and did this already but the queries look fairly the same but in terms the requests rather but in terms of the return type you notice that I have get leave request detail request showing the leave request dto however for the list and we discussed why we would separate the details earlier we have leave request list detail so the list is returning a list of the details specialized for the list and then the details is returning the detail with much more detail in it for the queries similar concerns for the get leave request list request Handler of course it is returning the list of leave request dto and the Handler looks fairly similar where it's calling the leave request repository and calling the get leave request with details similarly when we are looking at the detail Handler it's the same thing except we're returning just the leave request detail now while setting this up you might have noticed that you were getting a lot of red lines when your types mismatched and you know you if you had the wrong data type here or the wrong request type being referenced everything would break so it's very very strict if you told me that the request is expecting leave type request dto you cannot put any other data type here in that Handler that you're telling should deal with that request all right so you you can just be very very careful about that and once you get used to the pattern these things will come more naturally I can understand if it's a bit frustrating initially but once again you have the code to reference so you can always just pause when you need to and replicate these bits of code in your application accordingly now in our next lesson we're going to look at setting up our first command and the command once again would augment the data in the database so we're going to look at what it takes to set up a create command for any one of our domain objects welcome back guys in this lesson we're going to be taking a look at setting up commands so commands once again augment the data and we're going to be starting off with our create command now if you're looking at my solution Explorer you would notice that I have a few more files and I have a restructured dto folder so let me just collapse everything else so you can focus on that section so in the early stages of planning out this kind of architecture you're always going to be changing things around because it's good to get it right from now as opposed to later on when you have many different files and then you have more references to updates when you move these other files around so in the early stages of setting up the details I had indicated that you probably would want to have a folder for the details and then have the different types of details in there so we did that with leave request where we had the leave request detail and the leave request list detail inside the leave request folder so I've just extended that concept to the other details where I have a leave allocation folder and a leaf type folder and I name this one leaf type detail let me just correct that so inside of these folders we're going to have the different details and once again it is not absolutely necessary for you to have multiple details or details specific to a purpose but I'm going to show you why it is beneficial to do that sometimes so with leave type the risk is low we have leaf type detail all that requires is a name and the default number of days that to me that's simply enough this data runs very little risk of uh you know over or under exposing anything for any of the operations we can create easily using this detail we can list easily and we can look at the details it's very simple however with leave requests we had discussed that leave request detail has far more details in it in a list setting we don't need that many details we really just need the details of the leaf type requested the date it was requested and if it's approved now in the create we once again don't need to ask for the consumer to provide all of those details because if you compare create with leave request we really don't need the date action when somebody is creating a leave request when I am asking for a leave there is no date actioned so that doesn't need to be provided the date requested that can be put in By Us by the system we don't need to you know get that from the user or from from the consumer um the start and end date sure those are essential we need to know the leave type we don't need to know the entire object of the leaf type we only need the identifier of the one that is being requested and at that point it's neither approved nor canceled so I can have a specific dto and as I'm talking I'm seeing that I have extra fees in this but I have a create leave request dto which is going to have the start date the end date the identifier for the leaf that I've been requested and once again the system can see the date requested and I need to make this actually unknowable so I'm going to use this opportunity to adjust this so this needs to be knowledgeable but I don't need it in the in the create so I take it out of the create in the leave request I'm going to make it nullable because date action will really mean when was it approved or canceled right and then similarly I'm just going to do this right down to the domain once again it's good to see these things early and adjust them because we have made the databases yet so we don't have to worry about this ripping up too much all right so that is why I have a specific dto for creating the leave request different from listing different from the details in another vein we have the leave allocation the leave allocation has a number of these the details of the leaf type that is related to it the identifier and the period it's similar to the leave request I don't need the details of the leaf type at the type of time of creation so we'll talk about over posting it means that we're giving the client application the opportunity to provide too much data and then this is where hacking and bad data and uh people introducing anomalies in your database that's how that happens so this is a good way to restrict what can happen on an operation so now that we have a good understanding of why we have more details introduced let us take a look at the command so I'm going to start off with the easiest one which is the leaf types commands I'm going to go to request and I'm going to create a new class and this command is going to be very specific create leave type request so that is the request to create a leave type I'm going to go ahead and add it and make it a public class and then this one is inheriting like we know from I recall Quest and it will return I'm going to make it return an integer now this integer will be the name or sorry the ID of the value or the record that has been created all right so you create we're just going to tell you the ID of what you created we don't know what the clients may need to do after creation but we're giving them back the ID so if they need to go to the details page afterwards that's up to them but we're telling you it was successful here's the ID for the new record now in the command what we're going to have as we know by now is our matching Handler for this request so you inherit from I request Handler and I request Handler is going to be implementing the create leave type request go ahead and include anything that is missing and it will say it's returning an integer now when we implement the interface you'll see that we get a task returning an integer and our Handler now let's jump back over to the request for a bit and there are a few patterns that you might see in the request for creation one pattern is that people will actually write out the fields that you know when you are about to create a record for this you're sending over the request to create a record for that type they would put in the fields in the actual request to say these are the fees that you're allowed to send with the request and then in that moment the request basically serves the purpose of my detail that I just defined here no I like personally I don't like to mix and match I don't like to have details here but then when it's a Creator I have the fields here and then you know I don't know where to go and I need to change what because sometimes I don't remember instead I keep everything at a detail level and the request is really just a mechanism to transfer the data so the detail represents the data and the request is just that Transportation so with all that said I'm going to introduce a property in this request for leave type dto so this property is what the consumer will fill with the request and send it over so in our Command we know that we'll say request dot leave type detail that is where the data is so of course if we're going to be interacting with Leaf types and auto mapper then we will need our usual suspects in our Constructor to be injected and for Speed you can just go back to one of the existing handles and just copy and paste change the Constructor name and then we just include any missing references all right trying to work smarter and not harder so now that we have all the tools we need how do we set up our Handler to create this record but before I move on I'm going to make a slight adjustment so one other pattern that you will see and I think I'm going to use it this time just because it's for me it's cleaner instead of requests so when like how we're dealing with commands now it's not going to be a request because our request is when you're asking for something a command is when you're telling something you know you want a command so instead of us using request in the name here we're going to say create leave type command all right so by renaming it at the source I can just allow the intellisense to rename it across the board but I will rename the file manually so we have create leaf type command so we know for sure that this one is a command and it's obviously the Handler is supposed to be carrying out a command so command Handler all right and update any other references around the place so I think that is actually cleaner and easier on the eyes easier to distinguish between what I requests classes and what are command classes so for our operation what we're going to do is Define the leave type to be equal to and then we're just going to use Auto mapper to map into a leave type so we're mapping from the detail to The Domain object this time around so mapper.map leaf type interleave type and we're looking at request dot leave type dto all right so we just go ahead and include anything that's missing there we go so now we'll say leave type is equal to get me the mapped version of that into the domain object then we carry out our and I'm just going to say leave type is equal to and I'll wait and we're going to call our leave type repository dot add method Gods right so remember that ad is actually returning the object or or something of the same data type right so leave type is now going to be updated because after Entity framework which is what we're going to be using as our orm after it does its operation it's going to update the ID so we're returning the object with updated ID and now that we have that ID we can say return leave type dot ID there we go so now that command has been handled no one will look at it we see that it was really not that complicated to do it's just three lines we're getting the request with the data and then we're going to map it into the domain object we're going to then pass it over to the repository for the operation to occur and then we're just returning the ID and that is it for the create leave type command so you can actually just pause here and attempt to do it with the others I'm going to do it and then we can compare notes all right so I've skipped ahead and I've gone ahead and implemented the commands the create commands for the other two domain objects so if you look at it carefully you see that it's pretty much the same code apart from the names and the repositories involved it's pretty much the same code so this is the leave allocation command Handler you can pause you can replicate it if you need to but that is our create Handler and our create request it's just taking that create leave allocation detail instead of the leave allocation detail all right similarly for the leave request same code same structure right and then the command it's just taking the leave request detail the create leave request detail so you see that all of these kind of look very similar so you can go ahead and replicate those in your code and when we come back we will look at the other commands which would include update and delete all right guys welcome back as you notice my screen is blank in this lesson we're going to be talking about adding the update and delete handlers and all of the assets that go with them so my screen is blank because I've added quite a few assets and I'm going to go through them one by one with you and you can go ahead and replicate them but I want us to understand the decisions that we're making at this point as they are critical decisions and this kind of architecture the things you put in there all decision based once again they are relative to what you're working on your team and the overall application and what you hope to accomplish so let's start off by looking at the details we already went through the details and we kind of separated them by folders so that we can see you know all the details relative to our domain type quite easily but then at this point we had one detail for leaf type and we had said that okay that was low risk because it could be used for many different operations I have since broken it out into two and the reason for this is you have create leaf type detail different from leaf type dto now why because leaf type detail inherits from the base detail and base detail remember gives us the ID now the risk of this and once again the purpose of the detail is to kind of reduce what we call over posting if I am creating a leaf type I don't need an ID I don't want to give the consumer the ability to provide an ID because that would just give problems I'm giving them exactly what they need to get through their operation so I created a new detail for leave type where they only get name and default dates they can't provide an ID field leave type detail can be used for everything else for editing for viewing because well it has those fields as well as the base which is the ID now as you may end up getting more and more details and you have feel score you know repeating across the different dtos then you may want to consider having a common folder inside of that subfolder already to kind of Define base properties that this dto must have anyway so any leaf type detail that will come up with must have name and it must have default days you could Define a base class if you needed to all right now we can move on to the leave allocation so I have three leave allocation details at this point and I'm going to point out a mistake I made in one of them this mistake was to have create leave allocation video inheriting from this dto alright so you have to be careful about these things if we're trying to be strict so that was a mistake on my part create leave allocation detail once again should have absolutely no reference to any primary key whatsoever but then we do need the other fields the update however does need access to the base dto for our updating purposes now it could be that we said okay well once again create that base detail that everybody inherits from or we could just buy the bullet and say we'll use one for create or update if the ID is provided and we know it's an update if it's not provided then we assume it's a create those could easily be arguing so I'm not saying no I'm not saying yes it depends on how granular you want to get and these are your decisions to make based on your context I'm just pointing out the differences and the risks accordingly so I am going to be breaking them out like that now for leave request it goes to even another level so we do have the leave request detail we're familiar with that we have the list detail which we already established why that is different we have the create which once again is incorrectly at least in my context inheriting from this which I'm going to correct right now and then I have two I have update leave request detail different from change leave request approval detail now you're going to ask okay so why have both because both are talking about augmenting the data right well once again it's a matter of how strict you want to be so the update serves the purpose of allowing the user or the consumer to allow the end user to update their leave requests they want to maybe change the start date or the end date maybe they chose vacation when they should have chosen sick maybe they want to put in new comments or they just want to cancel it so I'm giving them exactly what they can do using this dto if they send a request to update these are the only things that can be updated however change leave approval request sorry leave request approval details sorry would have only the ability to change is it approved yes or no so the approver is really just saying yes or no I mean if you had more Fields like additional commands and you know anything like that you could add them into dto of course they would have to be present in the domain object but my point is that I am using the detail here to help me enforce certain business rules and certain behaviors that my application is capable of and and once again I have seen situations where there's one flat detail and decisions are made in the handle that based on the data present maybe in the request or in the detail this is the kind of operation to be carried out so it depends on how much you want to break it out to have that level of granularity so you know if it's an approval request you know exactly which Handler to go to or you can have one big command Handler that is taking the data and a bunch of if statements to say if it is if the ID is present then if it is not present then update but then if it is present and this flag is not null then assume it's an approval you could do it that way but I'm not doing it that way I prefer to know that when it's an approval request I have that change approval command if it's an update it's an update command I know exactly where to go to do what so now that we have that dto explanation out of the way I'm going to jump over to the features folders in Futures in leave allocations and leave types at least I have already defined the new handlers and their commands so let's take a look at the simpler one so we have the update leave type command and this command for the leaf type is just taking I request or inheriting from our request as we know but then it's returning what we call a unit so if you just hover over unit you see that it's a mediator provided construct that represents nothing like void right no content so in API design when you do an update you would usually return a 202 if I'm not mistaken which is short for no content so it means it was successful but I have nothing to show you that's basically what unit is all right and then we're taking that leaf type dto as the property I haven't implemented the the commands just yet in the Handler so we can do that together but I'm just showing that we have that same construct for the update leave allocation command where we're taking the update leave allocation detail and returning that unit and we have that command defined accordingly also empty so we're going to do those two together because those are pretty simple and then we're going to spend some time exploring the leave requests and the business rules there now the workflow for our Handler and I'm going to start off with the leaf type command Handler all right the workflow here is that we need to one retrieve the original record to update that original record and then three send it over to the database and then return the unit or at least something to say it was successful so two approach is one you can use the repository to have that specific method because then in the case of the leave requests there might be specific methods and then once again you're going down that rabbit hole of having very very specific methods in every single repository along the line or you can just do you know most of the work inside the Handler which is what it's for anyway right so I'm just going to say VAR leave type is equal to leave type repository dot get and then we're looking in the request looking in the leave type BTO looking at the ID now another design pattern that I have seen is when it's an update leave type command they would use the regular leave type let's say the one that does not have the ID but then put the ID property inside the request or the command object so that way when you are making the update you include the ID inside of this object and then the detail is just itself there are so many ways to do this and once again once you understand what you're doing you can do make the best implementation based on your context so here leave type is going to be retrieved based on the ID of the payload coming in with the request and then we can say mapper dot map and then mapper.map is pretty much just going to in this situation get the request dot leave type detail and notice that I'm not specifying a data type this time I'm using parentheses mapper.map open parenthesis and then I'm saying this is the source of the data and I want leave type that just came from the database to be the destination of the data and I'm getting that green line because I failed to await on that line I apologize so there we go so my product map and then it's saying please just you know update whatever is on the right with whatever is on the left that might be different whether it's different or not just please update it because the update is going to send over and that's why our detail needs to have as many fields that match the the data the domain object itself as possible it's going to have a name it's going to have default dates we don't know what has changed so that's why we're seeing Auto mapper just update all the values so if they blanked out the name then we're going to update it to a blank name hopefully they didn't however if they didn't change name then the expectation is that the same name is going to come back so once again we can't account for what might have been changed so we're just saying please update the leave type with the corresponding values coming from the object in the left and then we're going to await our leave repository update and then this is where we send over our leaf type post mapping we're sending it over to the update and then we just return unit dot value and that is it that is our update operation I have this red line up here because I have int and not units so after I made that change everything is okay so that is it for updating the leave type what the leaf type so I'm actually just going to copy this I'm not going to give myself too much work I'm going to jump over to update leave allocation and the only thing that we're going to be doing differently here is that instead of using the leaf type repository I'm going to be using leave allocation repository instead of saying leave type dto I'm saying leave allocation BTO and instead of calling the object leave type I'm calling it leave allocation everything else is pretty much standard and pretty much the same and this will handle our update request all right so I've gone ahead and completed the leave request commands for updating like always see now that it's not that complicated right so I've gone ahead and done the update leave request command and corresponding handlers or leave request command Handler taken from the command returning unit and it is just the only difference once again is the repository being used but it is pretty much the same operation now one thing that you may want to consider is the specific business rules around this kind of operation so yes the code looks the same but then when updating a leave request there might be other things that need to happen right so in the case of the change request change leave request approval where we only get is it approved or not we also need to set the action date we also need to probably update some other things so I think it would be good if we had a specific function in our repository to handle the change request now the cool thing about requests is that we don't necessarily have to have a request per our request per all the time I could actually reuse the same request and Handler to handle this kind of operation so let's look at this situation so inside of the update leave not leave allocation apologies inside the update leave request command we could have the leave request dto but I could also have a property of type change leave request approval dto so this request is capable of having either one of these objects now in the Handler I can make a decision and call the appropriate method based on this because it's still an update Command right so inside of this update command Handler I can put in a bit more logic I can see if request dots leave request detail is not equal to null then this is the route I wish to take I can say else and I'm going to be very explicit with this else because I don't know if maybe in the in the future I may have some other business rules so I'm just going to set up for these two explicit situations where it's either that the this should be else if apologies else if lcfrequest.change request approval detail is not equal to null then do that right and at the end of it I'm just going to try and retain one return so I'm going to take all of this and say you carry out this operation when the leave request dto is not equal to null so that means reverse consuming whoever is interacting with this Handler or sending over the request needs to ensure that they fill the the appropriate Fields according to what they want so I'm just showing you different flavors because you could go the request Handler pairing for every single situation every single scenario but then you can kind of Bolt them together like I said the Handler some people put a lot of business logic in this section so once again that's up to you so if the change leave request approval dto is not equal to null we have a decision to make what exactly are we going to do we know we have to retrieve the leave request one way or the other we're not going to do the comprehensive mapping all we really want to do is eventually call the updates but with other things happening so I'm going to call a weight leave request repository change approval status no what what do we do I could give you the ID I could give it the leave request object as well as the the status that it should be changed to there are a number of approaches that we can take now we always talk about repeating code right so let's say I do this I go and fetch the leave request and then this will be relative to the change leave request approval details ID and then I can say give this operation the leave request that was retrieved as well as the value from the the detail field for the approval whether it's approved or not all right now I'm repeating leave this call to get the leave request now I can only made this call relative to if it was leave request detail or change leave request detail that came in because if this is not then I can't get that ID and if this is null so I have to make a decision so you see all these little things now okay let's refactor so to make our life easier we're going to go back to the the command and then I'm going to say well no I see a good reason to tell the consumer include the ID the ID must be present in these either way but do include the ID here so when you include the ID there I can easily say request dot ID from outside of the if block and then I know I have the leave request that needs to be modified now if it is that the whole detail came over then fine I know exactly what to do if it is that just a change request I don't have to go and find it specifically but then I have it already and I can just pass in the approval status so this method it can get implemented in our Ile Repository and I'm just going to make it a void so it's just a task and the parameters would be leave request and a Boolean well it has to be nullable Boolean of approval status all right so then when we call that we're just passing those two commands appropriately so this is one way of writing the code I'm sure you're probably sitting here and saying okay well we probably could have done it this way or I need to do it this way for my situation that's fine but as long as we understand the flexibility that we have when it comes to that whole request and Handler Pipeline and how we can handle different scenarios we can use the one Handler to handle the different potential scenarios based on the request based on the data provided in the request and you know you don't have to have a peering for every single scenario that you might have but you can have a Handler to cover multiple scenarios all right so now that you have the hang of it I want you to go ahead and implement the delete commands and handlers so I've gone ahead and done that and we have the delete leaf type command which is inheriting from I request so notice I don't have I request and a data type last time we used the unit so this is just the point of that you don't necessarily have to put on that data type if it's not going to be returning anything so this delete delete command will have a parameter for the ID and then inside of the Handler all we're doing is retrieving the appropriate lead time based on the ID and then we're sending it over to the delete and then we are just returning unit dot value and at this point that is the general theme for them all so it's the same thing for the leave request now whether or not you're going to actually expose functionality to delete a leave request that's entirely up to your business rules because it might be that there is no hard delete it's only a soft delete or delete really means cancel right so that would just it would just flag it that it was canceled disregard it but keep the record so I'm just showing you how to put in the functionality but then once again the business rules and the application thereof are relative to your situation so that is it for setting up the delete and update handlers for our domain objects and pretty much that's the gist of the whole mediator pattern coupled with the cqrs pattern so as we go along what we're going to explore is making this a bit more bulletproof because right now anything can happen anybody can come and create anything and there are no real rules to govern what is valid versus what is invalid so we'll try and look at that how we handle invalid data coming in and how we can make it a bit Universal and foolproof all right guys welcome back in this activity we'll be setting up validation for our details and our commands now before we move on there's a quick correction that I want to make for the code I wrote in the update leave request command I had inadvertently used the leave request detail so if it's in the update then it should be the update leave request details so if you caught that error and you carted it to yourself then kudos to you if not then you can go ahead and make this change with me no problem now what we are talking about when we on the topic of um validation is the ability to make sure that the data that we're receiving before it goes into the database is well valid because as it stands there is nothing here to stop us from committing invalid data to our database and one thing that is very very very important is data Integrity so you don't want to create records with vital data missing leave allocation we don't know what leave type it is stuff like that so you want to validate it and then reject it of course if it doesn't meet the standards now when you're if you're used to MVC and you think about validation and you're saying that on the models we could easily put our data annotations which is very true um I have found this to be useful but then when you want to extend beyond the default ones you have to start building out extensions and so on which is which is also very good but then in this particular program we're going to be using fluent validations which is a library that allows us to use the fluent syntax and build out very very powerful rules and validation structures around our properties in our classes all right so to get started we're going to jump over to nuget and I simply searched for fluent and you see all of these wonderful search results popping up now a point of information the documentation for this library is very good and you can find it on the website fluentvalidation.net and you'll see how you can extend this and massage it and use it to its full capacity to help with your validation needs so I'm going to go ahead and install this library for the dependency injection extensions and once that is done we can close nuget and then get over to our setup but then one thing to note I don't think I mentioned this before when you click on the Cs approach file you actually see which packages are installed and their version so alternatively if you know the exact package name and version you want you can actually paste a line like this inside of your CS brush file do a build and it will automatically get that package from nuget for you so that's our way you can also install some of these packages going forward so let us start with our validators now I'm wondering where to put these validators I'm just going to collapse everything so we can see all of our folders kind of compressed all right and then of course we have the details the details are where our validations need to happen because they are the ones taxing the information on our behalf we don't need to validate the ones that are being used for the queries that it's a kind of useless right because the read operations don't need validations they write operations or the augmenting operations however do so I'm going to in one of the folders let me start off with the easier one I'm going to add a new folder and I'm going to call it validators and then inside of this I will add a new class and then this one is going to be create leave type BTO validator of course we make it public and then I'm going to let it inherit from abstract validator and then I'm going to pass in the name of the exact class that it is relative to so I'll just go ahead and include any missing references and then it adds that using fluent validations library and then we're ready to go so what we have is a Constructor tab tab and we get that Constructor and then we can start defining rules so let me just take a quick look at the create leaf type detail what would we want to validate on this well we would want to make sure that a name value is provided right we also probably can limit the number of characters that this name property can have um you know it's a musliminal and it must have a maximum length and it will probably want custom messages for situation for the default number of days we can probably say that it has to be more you know more than one it must be greater than zero at least for the default number of days so there are a number of things we could validate here so what we'll say is rule for and then you notice that this looks just like the same Lambda Expressions that we're used to and if you're not quite used to them that's fine we'll get used to them eventually so it's rule four and then we can say name and the cool thing about fluent validation is that you can chain things along so you can chain it along and say okay this Rule and that rule and that rule and that rule so the rule for p dot name is let's say not empty so that means it must have a value and then I can say with message so if it comes over empty then we want this message to be printed so I can do something like this property name so that way I don't have to type name must be name is required right because then I make a dynamic if we change the name in the class itself then we may forget to update the message accordingly so by just doing this it will automatically inherit whatever name or whatever the name is of the property that it is relative to right so we'll say property name is required that's our validation message another validation we could put is not null so we're letting it know that this should not be null and I put my semicolon prematurely sorry about that so it should also not be null let's see what else we can have we can also say that the maximum length of the name property is maybe 50. there should be no leave type with a name that exceeds 50 right and then we can add another with message to that with message all right so I'm just giving you ideas I mean you may have different um requirements for your validation than I do but these are General guidelines that you can follow so let's look at the the P dot default days so for default days you notice know that because the data type is different some of the validations might not necessarily apply so I can't talk about maximum length with the default days that has nothing to do with an integer right you see that the errors are gone so I'm saying it must be present but then it's integer so it will always pretty much it will always be present but we can leave that alone but it it shouldn't be empty but then it can never be not really and truly because integers default to zero when no value is provided but then we did say that it must always be greater than zero and then I'm sure that there's a less than so let's just say we want to say in the system there should be no leave type that is put in that has any number of days greater than a hundred or up to 100 and it must be at least one so the different data types can get different rules and we can chain them along as necessary we can put our messages accordingly so I can put my with message here with message here so with those validations in place on the create leaf type dto let us see how we can go about making sure that these validations are run so in the command that creates the leaf type right we do get that leaf type dto from our Command object right what I'm going to do before I even do the mapping though because I don't want to waste resources on an operation with invalid data so I'm going to do the validation first so I'm going to say VAR validator is equal to New Leaf type dto validator so while it's still a detail before I try to even map it over to the domain type I'm going to invoke that validator that I'm going to say VAR validation result is equal to and I'll await my validator making the call to validate and we have the async option hence me using the await and then we pass in the object to be validated which will be request dot leave type dto now at this point the validation result is going to either have errors or not so I'm going to say if validation results dot is valid so we get that it's either valid or not based on the rules it's going to be valid or not if it is or let's say if it is not valid and then for readability I'm going to say if is valid is equal to false right because sometimes in our fairness when we do just use exclamation signs sometimes when you're tired you might even miss it when you're reviewing the code and so on so I'm just going to be a very explicit if is valid is equivalent to false then I'm going to Simply throw a new exception so if you're used to exception handling you know that once an exception is thrown that's it it basically crashes the program but though later on we look at better exception handling and how all of that can actually help us to write a bit cleaner code instead of having a bunch of if statements to check a bunch of things you just have exceptions that are being thrown strategically to help the flow of the application so in this situation if it is not valid then we're just going to throw an exception we're going to look at how we can make ex custom exceptions also which can be handled different from actual fatal exceptions so that's pretty much it we're adding validation here to make sure that it doesn't go any further it doesn't go anywhere near the database so don't you want it to become a domain object if it is not valid now let's try probably the most complicated one so I'm going to challenge you to set up validators for the leave allocation which is really not that different we just need to make sure that the number of days is present and it's more than zero um the leaf type ID cannot be null it has to be greater than zero also and then you could even extend it to make sure that the leave type ID exists in the system because if somebody tries to spoof and send over a lead type ID that doesn't exist in our table then that is also a validation error that we can actually catch before we try to commit the database I'm coming to the database and we can do that for the period so I'm going to challenge you to do that one but we're going to work on the leave requests together because this one is going to have a few more things in it so once again I'm going to add a new folder validators and then let us start off with the create leave request detail validation what do we need to validate well our dates need to be valid dates we still need to check the leave type ID so we're going to do that together and well that is optional so that's fine so let's go into that one so we start off with our class create leave request detail validator I make it public and then I am inheriting from abstract validator relative to our create leave request dto alright so I've already written some of the code for you and we're going to go through it it's not completed because I want us to do certain parts together but rule for start date it must be less than the end dates now we saw that we could also use the scalar value here so I could have put an integer but then an integer would be an incompatible comparison with a date time so I could have put date time now right just to make sure that the start date is not before today or it must be before today which is not necessarily the case right so based on the business rule you may want to compare accordingly but this business rule states that the start date must always be less than the end date and then with the message I can say property name must be before comparison value so in our create leave type dto we had hard coded the 50 we hard coded the the one and the zero here but we could easily see replace them let me spell comparison correctly we could easily replace those areas with comparison value I'll leave the one hard-coded for now but I'm just showing you your options right so I'm seeing that start date must be before end date similarly for end date it must be greater than the start date and property name and comparison value all right now relative to the leave type ID I did say that our validation could take a number of forms one you want to make sure it is greater than zero okay fine another more important one though would be that you want to make sure it exists now if we just check if it exists even if they sent over zero zero would never exist as a leave type ID in the database so we could chain it along because then we could waste that database call by just doing that so I could say greater than and then I'm going to say zero and then I'm also going to say it must exist so I'm using what you call a delegate here and I'm going to just erase all of this and retype it from scratch so you can see exactly how it looks we're going to say must async open and close parentheses it's async so we're going to await but then we're going to define a delegate sorry we're not awaiting we're letting it know it's an async delegate which takes some parameters in this case we need the ID which is the value so we're taking that value as a parameter number one and then token is a cancellation token as parameter two and then I'm using a Lambda Arrow to then Define some object block or well method block so this method block is where we'll carry out that check to see if it exists now you're probably wondering okay that means we need a database call how exactly do I call the database from just a validator the cool thing about this is that it allows us to directly inject our dependencies all right so we can continue by injecting our repository so we know how to inject already we'll put it in the part in the Constructor and then we can use control dot to initialize the field I already switched over to my underscores which is optional of course but using that we can inside of this must acing delegate function check for the existence of the leaf type repository so two things to note here or three things one we're injecting so the validator allows us to inject other dependencies like our repositories that's one two we can actually have a custom function doing customized validation first I'm going to type this again for you from scratch so here we say dot must and we have Mustang the async that's fine so most async and then because we're using async graph to let the delegate know it's acing so the delegate is going to take two parameters ID representing the very ID that we're validating or the value we're validating and token would be representative of the cancellation token and we use our Lambda arrow and then we open and close curly braces then inside of these curly braces we have our logic so the first line of our logic is to check or repository if the leave type exists and then return that it does not exist all right now this function I just created so I just extended our generic repository to have a method that returns a Boolean it's called exists and it takes int ID so this you can add that to the generic repository and you can use it across every one of them but the point is that we can now use that to check if anything exists in a particular table and in this situation it's a nice shooting to check if our leaf type ID exists so now that you're equipped with how to handle that leaf type ID I'm going to challenge you to go and set up validators for the leave allocation so hit pause take a few moments set up the validators forward leave allocation and any other detail that we haven't looked at just yet and then when you come back I'm going to show you another way that we can refactor our code to kind of reduce on the repetition all right so I hope that you actually took the advice that you went off you tried to do it yourself and that you had some amount of success that's good but then I want to show you just another level that we can take this to so back when we were setting up the details we kind of realized that would be ending up repeating our properties across multiple dtos for instance the create leaf type dto and the leaf type detail they actually have the same properties bar the fact that one relies on the ID which we serve up through the base detail so the validation rules for both of them will actually be the same except maybe the one that has the ID you want to have a validation for it so because one has an ID one does not and the validator so far have been very strongly typed because when we have the create leaf type detail it's only for the create leave type dto and update detail would have to have its own validator so what I've done is to extend it a bit and this is what they call pain driven development it means do what you can until it is no longer practical then you refactor right so when you're applying these solid principles sometimes you don't see it right off the bat but then at a certain point you realize that this is getting tedious or This is Not Practical this is not in keeping with the principle and so you refactor your code to get the most out of the principle at that point so at this point we're realizing that we're having the same validation rules split across multiple files which is fine or at least having multiple files for validations is fine but having the same rules repeated can be dangerous because then if the rule needs to be changed in one we could change didn't want to miss it in the other we know that risk so what I have done is to have an interface which is an abstraction of our Fields all right so like leave type dto I've created I leave type detail and this has the fields that we know the leaf type detail needs to have so in the create leaf type detail I have let it inherit from I leave type dto so these two fields are just the implementations of what have been defined in the interface just the same way in leaf type BTO while it does inherit from base detail it also inherits from I leave type detail so leave type BTO would have the ID as well as the properties coming over from our interface now okay so so the next step is that we can create an eye leaf type dto validator meaning I am validating against the interface so my rules are no longer directly applied to the leaf type dto they could be that's fine but then like we saw we have to have multiple because we would have to have one for leaf type B2 and one for the create so instead I can set up validations against abstraction both dtos actually inherit from the abstraction so these rules will apply to both of them and then when I have to get customized I have my create leaf type dto validator in which I say create leave type of detail validator and everything that we know already but then in the Constructor I'm simply calling an include method so this is fluent apis way of allowing us to have validators that are apply to other things apply to another class so this really applies to the interface what I'm saying when I am doing this create leaf type detail validator include the rules from the eye leaf type video validator and then I can have my custom methods also so in the update detail I could have the same kind of um syntax but then it's the update which means I also need a rule for and then I can say I need a rule for the ID Fields I can say p Dot and then see it's giving me all of the properties including ID because it's against that type so my validation for the ID is that it should not be null and it should come with a message property name must be present because of course when you're updating you need to send back the ID of the record that you're updating which is why we do need that validation rule for the update and which is why I would have to have the separate file for the update but this is much cleaner because at least we don't have to repeat the rules for the name and the type or the name and the default days sorry we don't have to repeat that across both validators so you'll see that I actually did that already for the leave request and for the leave allocation once again for the leave request I have I leave request dto and it's the same code that we just looked at when we did the leave request detail validator with the injection and in this case we have to initialize it and then we do the rules but when we look in the create leave request detail validator we see that we have to do the injection so we still have to do our injection we have to initialize it and then we pass over that injection into the include method because of course the I request detail validator needs to have that injection so we can't just call it we have to provide that value for the Constructor so it's just a daisy chain but I think that this is much cleaner either way and we don't have to end up repeating all of these rules right across the board so you notice that both the create and the update look very similar except the fact that the update has that additional rule for the ID and just for completion we have the eye allocation details so I do have the idtos the interfaces so I didn't show that so anything that is common across everybody I just put that in the interface and then anything else can be puts directly into the detail as needed and validated accordingly but then for create an update those are all the things that are we really need we don't have to necessarily we can set up validation rules for the request commands maybe limit the length um we don't necessarily have to do anything for cancel but once again I'm just giving you the guidelines your business rules and requirements may be different but you set up your validations as needed so our update leave request detail inherits from the base and I leave request detail we don't have to do that for the list because we're not validating the list we're not validating the detail detail either but the create definitely has to inherit and then the change request approval well that takes from the base detail but we're not quite at some point we can validate this I'm not prioritizing it but then over update and create we definitely need to have ready all right now for our create allocation so we have the I leave allocation and then both create and update inherit from I leave allocation so I'm just going to jump over to the I leave allocation validator where we have rules for the number of days so this one is simple and as the application grows business rules change we can easily put our validation here without modifying the custom queries and any other customized operations around set business rules so rule for a number of days right now I just have it must be greater than zero and by validation messages were a victim of some copying and pasting so I'm just saying property name must be greater than comparison value for the greater than rule for the period so the period really should be the year right so for the period the year 2020 these were the number of days that you got that's the whole point of the leave allocation table in case that wasn't explained earlier so the rule for a period is that it must be greater than or equal to date time dot no dot year and we can boost this a bit more but for now we'll just use that so we'll say with the message property name must be after this year and then we all saw and wrote together the validation rule for the leaf type ID and now for the create leave allocation detail validator we're simply injecting the leaf Tire repository initializing it and passing it over in our include method and for the updates we're doing the same except we also have that rule for the ID so that is really it to validation yes it took a while to get there there were some refactors along the way but I'm sure you can see how it's all coming together to kind of reduce one repetition across multiple files and two kind of help to keep everything structured so one consequence of the following the solid principles of course is that you're going to end up with many more files which we discussed earlier but it is coming together nicely and helping us to reduce how many times we place the same thing in multiple places hey guys welcome back the last time we're here we're setting up our validations for our handlers and for our various details and in a nutshell we realized that we needed to put in some rules so that whenever we get the create leave type command with the create leave type detail or whatever dto we can run it against the validator and then we would return an exception if it is not valid so we should have done that across all the handlers for update and create anything that needs a validation should have at minimum these lines so I'll just click through and you can just go ahead and you know copy in case you didn't finish that up so this is for the update we just looked at the create for the leaf type update for leave request pretty much all of them look like the same thing all right they're all validating and entering an exception now I want to talk about custom exceptions and message responses right because at the end of the day right now all we're doing is throwing an exception now an exception can be thrown based on our throwing it manually but it can also be thrown because of something else it could be a database read write problem it could be something else right so it's always good that the consuming application or whatever is calling the Handler has a good idea as to what through this exception so the cool thing about exceptions is that you can extend them so the base data type for an exception is the exception that we have thrown here but we're going to create our own for the specific purposes so we're going to start off by creating a new folder in our project and we're going to call it exceptions and in it we're going to have bad request exception not found the exception and validation exception so you can go ahead create that folder and these three files remember to meet them public of course and what we're going to do is let each one of them inherit from application exception so exception is the base type of an application exception is used as a base type for application defined exceptions all right so we're just going to go ahead and let each one of our classes in heard from that now the bad request exception will later on when we want to Define that the requests that were sent over is just bad all right but for now we're going to initialize it or write the code to wire it up so all of them will have a Constructor and for this one the Constructor is going to take string message and then our base has to inherit the same message that is passed in base being our application extension so that's what that exception looks like application exception rather sorry about that now moving on we can do the same thing for our not found but then we can be a bit more explicit with certain things for instance if we're going to be saying not found we would probably want to say the name of what was being sought after and maybe the key value all right so we're passing a name and keyboard and the base requires a string so it has three overloads but we want to pass in a string here so we can just pass in our message that we know we want to print and my message is going to say that the name whatever it is and its key was not found all right so if they search for something it's not found we throw uh not found exception then for the validation exception we're going to get a bit more fancy so the validation exception is going to want to or we're going to want it to return the list of all the things that were wrong with the request or the data that was sent over in the request right so I'm going to have a list of string and I'm going to call it errors right and then in the Constructor we're going to have the validation results data type being passed in so validation results or validation result is coming from fluent validation so we'll just pass that whole object in there it is using fluent validation results right and then we can say we can initialize our errors let me just initialize that here and then we can say for each validation error in the errors or I can just shorten it and say for each error invalidation result dot errors we want to add that error to our errors list so I'm just going to say errors dot add and then we just add error Dot and we have an error message there we go so that error message would be whatever we had set up in our validators as the message to be returned when it is not valid so now we have our custom exceptions we're really going to focus on the validation exception right now though and so in our handlers we can actually update this from throw new exception to throw new validation exceptions if the validation result is not valid we throw this new exception and we pass in our validation results and you want to include any missing references so you see here it's asking for these but we know we have it defined in our custom exceptions all right so you can go ahead and update each line that was previously just throwing a new exception to not throw that validation exception and please remember each time that we're including our custom exception not the fluent validation or the data validation one all right so go ahead and update them all and make sure you're including the cart Library now at this point I can imagine that you're wondering okay so how can I use the other exceptions well let's look at the not found exception so in say the delete operation we have to find the record then do the delete and then return well the unit right but then what if we don't find that record well then that's a perfect opportunity where we say if the object that we're looking for returns null or if the operation returns null then we throw the not found exception and what would we pass into the not found exception remember that it takes two parameters it takes the name and the key so we could easily say name off and then this is a nice way to keep it strongly typed so we're looking for a leaf type so name of leaf type so we're saying the leave type with the ID that was passed in was not found or rather request.id right there we go all right so then you can start decorating your delete handlers with that one line so in the case of the leave request it would be the same thing except we're checking if the leave request is null and then this would be leave request not found go ahead and update so you can do that with the leave allocation also all right so once you're all done with that then you have set up some nice exception handling at least or custom exception handling in your handlers now another thing that we want to look at is custom responses so what happens when there is a positive result and even when there's a negative result right so this is where your your architectural needs May differ from mine in terms of what you want to do but here's a concept we can Define custom response types or have base responses where we can return data based on the situation so if it fails we could throw the exception sure or we could have a custom response that has a success is false flag it contains validation errors and so the client will always know that I am expecting a response of this data type that we should always have this data if the flag is false then I know it failed if it is true then I know it passed so we're going to look at something like that so kind of an alternative to just throwing an exception or returning just the ID what we could do is Define a new folder so we have a new folder here called responses and in it we have a file based command response and it will have three properties success which is a Boolean message which is a string and a list of Errors should we need to send back the errors right so then after we have this base command response we can extend it to facilitate the specific operation so for instance one result will probably want to extend this is that we want to return certain data each time a leaf type is created or updated right so the base response might not be enough so we can create a custom response associated with leave types so we already have handlers we have requests then we could create another folder called responses and then we could extend that I'm not going to get that complicated however what I'll do is just add another property here and I'll call it ID right or we can call it record ID so that means whenever something happens like we create instead of just returning the ID what I could do is and this is a huge change so let's go through it line by line and I'll address the red lines as we get there so initially we were just saying get me the validation results through an exception otherwise continue and then return the lever leave in this case leave request ID all right no what I'm doing is I'm saying firstly initialize the response so we have a base response that's fine then I'm saying if the validation result is false set the response dot success to false the message you can put in a custom message if you wish and then the errors we would like to fill with the same validation error so I'm just selecting them from the list of errors or from this collection of Errors so this select has a red line because I need an extra Library which is system.link so I just make sure that we could see that together and then it just gets the error messages puts them in a list and then that goes in so that's a nice one liner instead of the for each Loop right then later down we say if the ad was successful so what happens is that if this fails an exception would have been thrown automatically by Entity framework anyway so if this fails to happen then we get an exception so it would never get this far if this was not successful so then the success is true or response is secretion successful and then we set the ID so that's what I was saying that across the board were only returning IDs right we were only returning the ID for the newly created record you could have a requirement where you need to return the entire record at that point you could just extend base command response create a new class call it create leave request response let it inherit from this and give it the detail parameter for a leave request dto you do your mapping you return it like I said I'm not going to get that complicated right now we can look at that in our future considerations or additional considerations lesson but I just want to get this concept of a custom response across so then we return the response now this has a red line because we had defined our Command to return int alright so we can go over to our Command and let it know that I request is supposed to return the based command response all right and then our error will disappear let me jump back and we're back in our Handler we see that we can return response as soon as we also update the Handler right so remember that we have that command and return type here up here so let me just update that and then finally the type on the task for the handle all right so there so when you want to change out your return types that's all all you have to make all those changes once again right now base command response so if you want to get granular keep on saying you don't have to get as granular but based on your requirements you will need to or you may not need to I am not making it a requirement to go and create command responses for every single solitary Handler or command Handler that I have right now I'm just going to be using the base response and I'm also going to be making that change to the leave request for now at least so that you get to see the idea of how you can have custom exceptions and or how you can improve on that to have your custom some responses alright so we're back and we're going to be setting up our persistence project so let us get started by adding a reference to our application project so we have the domain project which has all of the entities and then the application project has a reference to The Domain project so our persistence project is going to have a reference to our application project all right so we can just click application click OK and then that's one dependency down we're also going to go over to nuget packages we're going to look for Entity framework but the one that we're going to be getting is Entity framework core dot SQL Server so this one when it comes down will come with all of the dependencies that we need so we can just go ahead and install the latest stable version and still in nuget let us just go ahead and search for configuration extensions and install microsoft.extensions dot options dot configuration extension so this will come in handy when we're going to be setting up some of our stuff so after we've done all of that we can go ahead and create a new class and I called mine the HR leave management EB context so create that new class you can call it something else you can probably just call it leave management EB context or DB context that's fine but it will be inheriting from DB context now DB context comes to this courtesy of microsoft.entity framework core so we can go ahead and make that reference and then we can make our DB context aware of the different entities that we had defined so if you're familiar with ef core then you know exactly what I mean so in this file we have a few things we have a Constructor where we initialize our DB context to have a parameter of DB context options of its own type and the name is options and we pass that down to the base which is DB context then we have our DB sets relative to our different entities so I can just go ahead and include the missing references for those and everything should be all green next up we're going to override a few methods so the first one that we're overriding would be the on model creating actually it's quicker to just start typing override and then you press space and then you'll see all of the options so we're overriding the on model creating so this method gets executed whenever the database is being generated right so we can set up certain rules so the rule that we're going to set up here for sure at least right now if we want to see the database we can do it from here but we're not ready for seeding as at least not yet we want to apply configurations from assembly and then we're going to say type of leave management DB context and I'm going to see dot assembly right so that is our putting in our on model creating at least right now like I said if we wanted to see the database or if we had special configurations for tables then we could always put that inside of this method so they get applied whenever it is generating the database model all right another thing though that we want to override for sure is our save changes so I'm going to choose the save changes with the cancellation token as its parameter and I'm going to outfit this save changes with some beautiful chord some nice hand decode that's going to allow us to do some audit logging automatically so remember that we had set up a base entity for each of these that came automatically with like a user created or created by rather I created date Etc so I'm going to set the for each Loop to go through each entry in change tracker dot entries and we're just doing an implicit data cost based domain entity and I can just go ahead and include that using statement for it and then for each one what I want to do is set the date and the date modified at all times so I can always say once you are about to save some change I want entry dot entity Dot glass Modified by Our Last modified date rather we're dealing with the date right now to be date time dot no right and then I'm going to do a check now to say if the entry dot state is equivalent to NTT state DOT added meaning it's you know it's being added it's a new record then we would want to set the created date to date time.no so we'll always our date created rather so we'll always set the last modified it once something is being changed about it we are setting modified date but then only when it's being added do we set the created date and that's that's like the most basic of um basic code to implement auditing that you may ever find once again this is automated so every time we hit save changes it does all of this and then it just calls the base save changes method in the background so that's it for Entity framework to our persistence layer when we come back we will start working on some implementations welcome back guys in this lesson we're going to be implementing our persistence layer so when I talk about implementing the persistence layer I'm specifically referring to our generic repository right so we only have the abstraction but we have no code to back this up so let's go ahead and do that so we add a new folder and I'm going to call this folder repositories and then in this folder we're going to add a class that will represent the implementation of the generic repository relative to type t so after generating the class we as usual make it public and then we make a relative to T and then it inherits from I generic repository which is also relative to T where T colon class all right go ahead and include any missing references and then allow it to implement the interface so I'll go ahead and write the code out and then we'll go through together now before we continue I realized that I got overzealous with some of the copying and pasting from when we were setting up the interface so just as some corrections for the update and the delete we can remove the T right we don't have to return anything when we do an update or a delete so those two should only be tasks so you can go ahead and make that change and then that of course will affect our implementation so our generic repository starts off with a Constructor that is accepting a parameter of type leave management DB context of course the DB context is basically our connection to the database so we do need it in our repository in order to carry out our operations our add method it starts off with awaiting a DB context call to add a sync where it just passes in entity if core is intelligent enough to infer What entity is being passed in relative to all the DB sets that have been defined in our DB context and by DB set I mean these so whatever data type is passed in it will know if it is one of the DB sets that it recognizes so we just go ahead and add the entity save the changes and then we return that entity for the delete once again remove the type parameter from task but all it's going to do is look and DB context find the set relative to T that it is being given and it's going to remove that entity from that set all right and then after that it saves changes so you'll notice that nothing really happens until you save changes this is that final commit to the database we have the exists method where we get an ID for our record and what I'll do is look for The Entity using the local get method which we'll look at in a few and then we return that it is not equal to no so when it's not equal to null then yes it exists otherwise that's false of course in the gets what we're doing is we're returning an awaited call to dbcontext.set T So once again we're looking in the specific set and we're finding the record relative to the ID all right for our I read only list T which is get all that's what it's returning all we're doing is looking in the set and we're doing a to list async on that set so we're just getting everything from that set and sending it to list and returning that in our get all for the updates what we're doing is setting the entry entity state to modified so that the EF core will start tracking it and then we go ahead and save changes so that is pretty much it for our implementation for the generic repository all right so now that we have our generic repository implemented we now need to implement our specific repositors so we can go ahead and add those so starting with the leave type repository we're going to look at what that implementation looks like so I've created the leaf type repository it is a public class called leave type repository it's inheriting from the implementation of the generic repository relative to the leave type all right and then we go ahead and say it is also to inherit from the eye leaf type repository so the red lines here indicate a few things one we need to bring in the missing namespace two we need to put in the actual implementation this this one right this interface didn't have any additional method so that's fine for now and then this is complaining because we need to have the DB context present for the generic repository so remember that when you're inheriting something that has a dependency you have to put that dependency in the inheriter also so that's a simple solution we just get the Constructor and then do our dependency injection and that is for the DB context of course but then we also need to let the base know that it can also use this DB context that is being injected and that's it for the leaf type repository so the contract didn't have any additional methods there is nothing extra to implement and because it's inheriting from the generic repository relative to the leaf type by using this implementation we have access to all of the methods that were defined here now let's look at a more complicated one so let's look at leave request leave request repository will have the same dependency requirements so we have to make sure that we inject the DB context pass it over to the base go ahead and include any missing namespaces and then we have to implement the interface so this interface actually had a few methods extra we had change approval status we add get leave requests with details and we had another one to get leave request with details by ID so a few things are happening in this particular one so the implementations here will be different from the generic ones because these are specific to some leave request related operations so the implementations are as follows for the change approval request we're getting a parameter of leave request and approval status where setting the approved state of the leave request to whatever value came over in the parameter and then we're setting DB context.entry leave request so you see this time it's not entity it's not generic it is very specific because we're in the specific repository so we're setting the entry State or the entity state to modify it for that leave request and then we save changes so we'll start tracking it and then save the change accordingly no you see that this is a very specific operation as opposed to the general update where we can't account for what is being changed so we just set everything to modified and allow it to track once again these are just ideas because maybe your business rules are far more complicated or the operation you have to carry out inside of the Repository he's far more complicated than just sitting one field so you may need a specialized function for that now for the get leave requests with details method all we're really doing is querying the leave requests table so Varley requests is equal to awaitsdb context dot leave requests and then we're including the leave type so we don't necessarily always want to include the leaf type we don't know under what circumstances we may need it so we have this one relative to the details that are needed alongside a record versus the regular generic one that is not including it's just returning data from the table so this time we're including details it could be this leaf type it could be more as many includes as you may need and then we're just pushing them all to lists and then we're returning for the final one where we're only getting one leave request with details based on the ID we're doing something similar except we're doing the include and then getting the first or defaults where the Q ID matches the ID passed in now we're doing first or default here as opposed to the find async that we did in the generic repository because of how these methods work you can't do an include when you do a find it just doesn't work right so when you have to do an include you have to use the first or the single or default whichever one you feel more comfortable with and then we return the leave request that has been found so we can jump over to the leave allocation and we see that it's a relatively similar implementation we have similar methods so I I put these methods in here just to point out that you can have custom methods in these repositories you may not necessarily need them in your application use them as you need them I also retain that red line because in case you're getting into all you need is to include that reference the EF core and then that is good all right so we have one major activity left and then we're done with the persistence layer and that is to set up the registration class for the persistence so just let go Application Services had a registration persistence will definitely need one so go ahead and add this new class I'm calling persistent Services registration it should be a public static class and then in it we will have a method that returns I service collection and we're calling it configure persistent services so of course as usual go ahead and install any or add rather any using statements that are needed and then inside of this method what we're going to do is write code to one register or DB context and add our repositories to the service collection and this is that full method of of course with the red lines because I always love to show you what red lines may exist and how you can solve them but this is what this method needs to look like so you can go ahead and start including and using statements that are missing so firstly we have the services.add context where we pass in the type that is the DB context leave management DB context and options dot use SQL Server so remember in the DB context we told you that we need to in the DB context on model creating we told it that it would be sorry in the Constructor right we took BB context options so those options are really coming from whatever options are defined here in the registration so we go ahead and use EF core for the use SQL Server configuration is coming in because we are going to be passing over the configuration from The Client app application that is implementing this call so the services bootstrapper and so we will definitely need to pass that in now config I configuration needs to be microsoft.extensions.configuration not Auto mapper so be very careful with that one so you can go ahead and include that namespace and then for repositories we have ad scoped so we're adding all of them as scoped but then for the generic notice that we're adding type of I generic repository with our angle brackets comma type of generic repository angle brackets but then every other one is the interface to the implementation peer without any angle brackets but I'll go ahead and add any missing references here and with that and oh I'm sorry I wrote the code wrongly here for this one ad scoped is open parentheses and no angle brackets for the ads code right so let me just correct that so you can see there we go so it's ad scoped parenthesis type of I generic repository with angle brackets comma type of generic repository with angle brackets and once again those are in parentheses what the others will have the angle back get surrounding the interface and implementation peering after all of that of course we return services so just the backtrack a bit to what this connection string will be we don't have an app settings yet so this is going to live in the app settings of the application that will be calling this method and so when it is calling configure processing Services it is expected to pass over that configuration object which will then give access to the app settings and we will be able to get that connection string to pass over to our DB context so that is what that whole line or that whole section is doing now the purpose of us using Scopes there are three injection models available to us we have ADD scoped we have ADD Singleton and add transient Singleton means that one instance of this service will exist through the entire application this can be dangerous based on the nature of the service and it could be useful for instance maybe a logging service that could be one instance throughout the entire application but then you probably don't want something like that for your database transactions because then when you have multiple database transactions you kind of want those to happen in a silo so that's why you would use scoped which means that for the lifetime of a request I am requesting something I am writing to the database I am calling your service for the lifetime of that operation then adscoped will you know invoke and connection to the database or an instance of this leaf type repository or any one of these repositories as it is called on during a request once our request is finished it will no longer be in memory so that reduces the chances of conflict and then add transient means that every single time it will always do something new which means that you might end up with more than you really need to complete a request which could also lead to conflict so once again you can use them kind of sparingly but within this context ad Scopes is the one that we want for database related operations now with all of that done let us do a quick build to ensure that we are right on track and that we have no errors and we have successfully built our project so when we come back we will start implementing our infrastructure welcome back guys in this lesson we'll be setting up our infrastructure projects now our infrastructure project is pretty much where the implementations for all our third-party services will sit in this lesson we'll be implementing an email service with the help of sendgrid and we're going to be setting it up in the infrastructure project now the first thing that we need to do is set up an abstraction for the email senders same way that we had abstractions for our repositories we have an abstraction or a contract for the email service now on that note I was looking back and I realized that the folder structure here is not very intuitive for the long run so I'm going to have to refactor here because I have persistence then I have contracts but contracts is the more Universal term because then you have contracts for the persistence layer contracts for the infrastructure layer and so on so I'm going to have to flip these folders around which won't be too hard I'll just call the persistence folder contracts and then I'm going to call contracts persistence now this is going to have a ripple effect for all of the name spaces because we do want our namespaces to be completely representative of what they really are so we have persistence that contracts now we'll have to change that to contracts dot persistence and then this is going to mess with all of the namespace references so I'm sorry about that but it's it's a refactor that is definitely required for us to have an intuitive folder structure right so after doing all of that if we do a build it will point out all of the bad name spaces that were referenced throughout our project see now quick way to go ahead and fix those bad namespaces would be to look for persistence.contracts everywhere and then replace it with contracts that persistent so you can just do that and meticulously go through and replace each term just to make sure you don't override anything that might be important and once you have exhausted that search you can go ahead and do another build just to make sure that you no longer have any Builders and once that is done I'm just going to close all tabs that were opened in that operation and then we can go again so in contracts we want a new folder and we're calling this one infrastructure and then inside this folder we're going to add a new contract or interface and I'm calling it I email sender now I email sender is going to be an public interface with a method that is going to be called send email and it will take a parameter of type email called email now we need to Define what this email looks like so I'm going to create another folder for models right so let me just add that folder we're calling it models and then inside this models folder we're adding a new class that we're calling email so this is going to be our template or model for what any email should look like and then this email will have the typical properties of any email the tool the subject and the body are string properties so now that we have that model defined we can go ahead and add the using statement and have that sorted out now before we move on from our model definitions we have another model that we need and this one is going to be for the email settings all right so it's going to host properties for an API key a from address and a from name all of which are string now that we have a few things flesh though with our email sender you're probably wondering okay why do I need emails so let me put it into context because we just started building out email service with no real context when somebody applies for leave or maybe their approval status has changed something like that you'd want to notify them that you know this action has taken place now where do actions take place well relative to Features we have our handlers so when you create a new leave allocation okay maybe you don't need to send an email but then I leave request would warrant an email to be sent whenever one is created or one is updated alright so let us look at the create leave request Handler where we can simply inject our I email sender and I'll just do that using the intellisense quickly initialize the field and then given our naming convention I'll just rename this using the underscore inside our Handler after everything has been successful right before we return and you know kill the whole operation so the Handler is still going on up until this line so we'll prepare an email object and then try to send it off and well deal with any exceptions so let's look at this slowly so VAR email is equal to a new email which is our model that we just defined we have the tool I just put in a fictional email there when we get to the whole use authentication and having actual user submit then we'll look at how we get the actual email addresses we have the body and the body of this email just says your leave request for and I'm just putting using interpolation to put in the content um start later end date has been submitted successfully and the subject is leave request submitted if you want you can further adjust the date by putting on Colon D so traditionally you would say to string and then specify the format but when we're using interpolation in this version of C sharp we can just put on colon and the formattings well the formatting string at the end of it and that will take care of it for us so D would give you the long name Monday June these dates this year all right so that's it for our Handler now that our whole application knows about the I email sender we need to work on the implementation so the implementation of this will live in our infrastructure project so to get started on that create a new folder inside the infrastructure project called mail and then create a class in there called email sender and then this class which of course needs to be public will inherit from I email sender so we can go ahead and then you realize that it needs a reference to the application so we need to go ahead and add that and with that reference added we can go ahead and implement the interface so before we move any further we need to jump over to new get and we need a few packages one is the same configuration extensions that we would have used from the other projects so a quick way to kind of manage common projects is to just go to the solution and say manage new get packages for the solution right so we already have some packages installed in some projects that we need in others like this one the configuration extensions so I can click on it and I see that it's already in the persistence project but I want it in the infrastructure project also I can tick it click install and so that can reduce the amount of time you spend on you get trying to find the same package over and over now the next package that I am interested in is send grid so you can jump over to the browse and just type in send grid and then you can get that latest version so you'd want to click it make sure you're ticking the correct project and then click install so after that is installed we're going to start wiring up this class so one thing that I'm going to do is set up a private field of type email settings and I'm calling it underscore email settings making it read only but then I am initializing it in the Constructor with this i options email settings parameter now let me explain what this is similar to how we had set up our database and we said that we have an app settings file that will be providing the connection string when the time comes it's the same way that we can actually pass over options or chunks of options or configurations from the from the whole app settings file which can be then deserialized into a whole object for us so what we're doing is saying get me from the up from the options or the app settings the email settings Json equivalent and send it over as this parameter and then we can just inject it in and then have it as our local variable or field in our class so this dependency injection is so cool because it makes everything so loosely coupled and malleable so let us continue with setting up our send email method so the first line that we're going to have is a client that is going to call or initialize the send grid client so we're just going to go ahead and add any using statements that are missing then after we get the clients we're going to have to get all the subject and the tool and the email body from our email object but the two and the from especially need to be a special data type so I'm going to say var2 is equal to new email address and email address here is coming from sendgrid so new email address and then we're going to have to pass in email dot two and then we're going to have to do the same thing for the from so I'm going to say VAR from is equal to new email address and in that one we're going to kind of put in a bit more in the definition where I'm going to say the email is coming from the email settings Dot from address and then the name would be the email settings Dot from name all right so we have the from under two defined and then after doing all of that we need to say message is equal to mail helper so mail helper is a I mean that's going to be a static class given to us by send grid that allows us to create single email there we go and you see you have different options to multiple recipients and more you know multiple emails to multiple recipients we're just doing single email in this situation but you you can see that maybe you have sent email send email to multiple send email with attachment Etc so you could Define different methods inside the e i email sender you're not confined to just this one that we're doing right so create single email and then we're going to have to fill this out according to how they've stated it in the in the parameters for the Constructor so the from comes first and then we say two we have those and then the subject I can say email dot subject here and the plain text content would be the email body and you can see that they have the plain text content versus the HTML content So based on how you encode your email you could you know put that email together accordingly right but for now I'm just going to say email dot body for both of those parameters so now that we have the message object formulated I'm going to say via response is equal to clients.send email so this is where we're actually going to send off that message that we just created of course we're getting that red line because we need to be async and once that is done we now need to return a Boolean based on the response I can just say return if response dot status code is equivalent to and I can just say system.nets.http status code okay and I believe that same grid also caters for accepted so I'm going to do both so I'm returning I'm just returning it's either okay or accepted so that is going to if it's either one of them then it's true if it's neither of them then it's false and they will know if the email was successful or not but the whole point of this once again and going back to our create Handler and the way that we wrapped it in the track catch the API that is calling this Handler or whatever code is calling this Handler should not be interrupted if everything else this is the most important part creating the leave request if the email fails it doesn't mean that it should crash the program so that's why we're catching the exception but we're not doing anything to throw it out or throw out the application now to top it all off we're going to have a infrastructure Services registration file just like with every other project before it so we have the infrastructure Services registration class being added to that infrastructure project and then we have the same form that all the other registration classes have had once again I configuration is being injected and the type that we or the namespace that we need is the Microsoft extensions configuration not Auto mapper and I'll bring it up every time because it has got me more than once all right so we're going to say Services dot configure uh email settings so This Is Us studying it that we want email settings I'll just bring that one in to be relative to configuration so remember I was saying email setting when we do the I dot options we're saying give me a chunk of the configuration that looks like the object email settings well what we're really going to be saying is configuration that gets section and it will look in the app settings for a section with the name and we'll be calling it email settings when the time comes so then that way it will know that we will formulate that section to look just like what we're expecting the class look like so we'll just automatically serialize into that hard coded class all right or strongly typed class rather next up we're going to say services that add transients now remember I was talking about the different models we have Singleton scoped and transient so transient means every time I get called I am going to be a brand new instance so we're seeing that every time I email sender gets called give me a brand new instance of the eye of the email sender class all right so go ahead and include any missing references and then we can close that one off and then we return services so that's it for us setting up our infrastructure at least at a very basic level once again any contracts that we'll have to Define for third-party operation will be defined in our application but implemented in our infrastructure in this lesson I want to walk you through what is required for net 6. so what I've done is I went through and I replicated everything that we have done so far in.net 5 relative to.net6 you probably have already been doing that but there are some nuances that I just want to walk you through and there's a particular fix that I'm sure will come in handy for you if you are proceeding with net 6. now like I have stated before I in the development of this course would have used.net standard 2.1 and I would have encouraged you since release of.net5 of course you can use.net 5 for all of your project libraries just the same way if you're using.net6 you can use.net6 for auto project libraries so for all of the class libraries just use net6 which of course will make all of the libraries and nuget packages that you import relative to the.netics version so for instance the persist distance which has all of the Entity framework the core Entity framework packages would be relative to.net 6 as opposed to.net 5. so of course nuget would kind of encourage you to use.net6 if you are building a.netics project in the API project you would notice that the file structure here is different from what you'd be used to if you have ever done apis or web applications in.net 5 or previous versions of.net core so generally you would have a startup file and a program.cs file and what happens is that the program.cs file is just a bootstrapper that is calling the startup file for all of the configurations that need to be present by the time the application runs in.net6 Microsoft has taken on a minimalist code file kind of stance so what they've done is reduce the amount of code needed because it's already implied we know it's a class called program.cs we know it's going to have a main function which is what executes so if you did like a.net6 console up you'd notice that that program.cs file doesn't have all of that coding overhead it just gets straight to the point so here we start off with the Builder and then another part of the syntax you'll notice is that it doesn't just say Services dot but no it says Builder dot Services Dot right uh for the and that's pretty much for everything and for configuration it's Builder dot configuration as opposed to just configuration so what would have been in the configure Services file of a.net 5 or net core 3.1 and prior um they would have had two methods inside of the startup file one that says configure services and the other that says configure configure Services is where you would put up all of the services and the configure would have the app or the middlewares so pretty much you start off with your Builder and in between the Builder starting off and the app saying builder.build that is where you're going to put all of what you would have put in configure services so that is why you see me registering the application Services infrastructure services and persistence and putting in all the other services that we know we need including the course um course course definition here so all of those things go inside of that section then we have the app section or the middleware search section where we can configure the different middlewares and the pipelines until we run the app so pretty much that's how that this new file is compartmentalized it's probably not as clear-cut but once you understand the pattern it should be fairly easy to appreciate where what goes now one of the things in doing this activity that I'm sure you're going to encounter and if you don't I would love to hear how you avoided it but I'm sure you're going to encounter or at least I encountered an issue when configuring the persistent services so when I run my migration I got an error that looks something like this unable to create an object of type the DB context for different patterns support to that design time see this link so that link will talk to you about some documentation and some ways to get around it and pretty much it wasn't really clear so I'm going to share with you exactly what you need to do to navigate this kind of error so once again persistent Services is what we're using to register Entity framework and all of the accompanying repositories that are dependent on it so when I jump over there you'll see I even put a breakpoint here while I was trying to figure out what's happening so when we jump over there what you have what we have is our registration of the DB context all of the repositories and then we return to Services what I have added to navigate that is a design time Factory so if we were to look at the documentation they would say that one you should have it in the injection bootstrapper which we already do but then this is actually an issue that goes a little way back with having multiple projects and having the registration in a different project from the actual starting project I didn't encounter this with previous versions of net core I'm sure it's because they probably addressed it but it has reappeared in.net6 and we're here to address it this time so what I did was I created a file here called ADI alivi leave management DB context Factory that should be Factory there we go so leave management DB context Factory and this inherits from I design time DB context Factory relative to the leave management DB context as you can see that's a file so I'm going to that's a class so I'm going to move it to its own file so I'm just going to control dot move to type of the same name as the class so now that that has been created just jump over and we can go through it together so once again this is the leave management DB context Factory I design time DB context Factory relative to the leave management DB context and then inside of this once you once you have that inheritance you will be forced or strongly encouraged to implement this method so it's public leave management EB context create EB context and it can take arguments which we're not really going to use in this situation so then we have the eye configuration root configuration is equal to a new configuration Builder and then we have the set base path to be the directory which is the current directory wherever the persistence project is we're adding the Json file called app.setting app settings.json we know where that's coming from and then we say build so this is just us building up what we want to provide the configurations to then build out a service so then we say VAR Builder is equal to the new DB context options Builder leave management EB context and the connection string is coming from configuration.getconnection string we're familiar with that particular line and then we tell you that we're using SQL Server relative to the connection string that we just received retrieved and it will return a new leave management DB context with the builder options present all right so in order to accomplish all of this though I did need some additional libraries so I needed microsoft.extensions configuration extensions configuration that abstractions file extensions and Json so you can just go ahead and retrieve all of those additional libraries so that that bit of code can be written successfully so once you do all of that and you attempt a migration again then you will be successful right so I I'm just I'm making sure that you have all the tools you need to be successful especially given that this is a little jump there's a little learning curve with.net6 and there are certain things that are different certain nuances so I'm just making sure that you have all the information you need to be successful at the at developing this project so I am going to share this source code with you so you can just go ahead and use it accordingly if you need to in this lesson we'll be looking at adding mediator services to our API now the context for this is that mediator allows us to specify behaviors in our application based on a response and Handler type of relationship and one of the consequences or benefits from this is that we can ship out a lot of the heavy operations from our calling code which in this case is going to be our controller and we can abstract that to somewhere else so the controller really just knows I build the request and I send it off to be handled so for context I have on screen the controller from the previous project which is inspiration for us redoing this leave management system and here you'll see that we don't have thin controllers we have fat controllers so remember that the controller really does exactly what the name suggests it controls the flow and you know everything that the application does so it responds to a user's request for data Etc now in the older project we had what we call Fat controls where we're doing everything inside a controller once again this works so it's not that it won't work if it's done that way it will work but is it the best practiced how maintainable is this because if I wanted to verify that these operations are being done successfully I would have a lot of difficulty unit testing it in this fashion this is not in a unit this is in a method inside of a controller so that increases my inability to test the parts of the application to make sure that they're functioning properly and it increases my time spent troubleshooting and regression testing and all of those things here it's checking if something exists and if it doesn't exist it's returning not phone and then it's doing mapping and it's doing a fine and then it's returning the view really and truly we just want as few calls as possible with no business logic this is some form of business logic where you don't really want that in our application right here's another situation where we're creating a record and we're just doing too much in this action so those are the things that we want to reduce when we talk about having thin controllers so let us get started by installing mediator in our API project you know the drill you can just right click go to new get research for mediator and go ahead and install it once you have completed those steps once you're done with that let's go ahead and add a new controller to our project it's an MVC controller and we want an API controller with redirect actions we're going to start with the easiest one which is leave types and go ahead and add now let's explore how mediator will kind of help us along right so we already have the basic crud actions being generated for us thankfully but then what we need to do is inject our mediator object into our controller so we are going to have our Constructor and then we're going to make reference to I mediator which will require us to have that using statement as well as to initialize that field and then we can start using this mediator object to orchestrate our calls now a quick tour of this controller and at this point of course I'm assuming that you have some familiarity with controllers and by extension API development when we want to get the list of Records or all Leaf types in the database we're going to hit this method which is just the git so it's API slash leave types that's what's expected to get us but all the leaf types and then each of these methods would carry out the other crud operations like the post the put the delete put is for update all right if you're not so familiar with what I'm talking about I would encourage you to go and check out one of my API development course is so you can get up to speed and fully appreciate what the intricacies are Behind These methods and how they work so let us continue for the get that is expected to return all the leaf types in the database we're going to have code that looks similar to this we're going to have VAR Leaf types is equal to an await to the method send found in our mediator object now what exactly are we sending if you look at the overload it is expecting an object of type or an object with the parameter called request so it doesn't know what kind of request it's going to send the request and the expectation is that it's going to get something that can be stored inside of leaf types now what requests would we be sending well jumping back to our application project features leave types and queries we would see here that we have the get leave type list request which is expected to return the list of leave type dto so in our Leaf types controller I would say I am sending a new object off get leave type list request and then go ahead and include any missing using statements and then I will go ahead and change the method header to public async task action result list leaf type details so now it knows that it's expected to return and action results that has that list of leave types so this return statement is no longer valid since no I will be returning leave types and look at that two lines for context I'm just going to compare with the old code all right so our old or old action would have had the wire Leaf types it would have actually orchestrated that call to the unit of work to get the records bring them directly back and then we'll be carrying out the mapping because it would be returning the domain objects when we would want VMS or you know context only this the same thing as a dto and then we would be doing all of this operation inside of the action itself before returning The View in the new paradigm what we're doing is we're just letting mediator know that we are requesting the leave type list our Handler is going to carry out all of the operations it's going all of the mapping and the querying and everything and it's returning just the objects that we need to know about so the API would never ever interact with the actual domain objects coming from the database we do all of that transformation before it comes all the way back so let's fast forward a bit to where I've already written the code but as usual I'll go through it slowly and explain each line so you can fully appreciate what is happening you can pause as needed and replicate and we will go through it together anyhow all right so one quick adjustment to the HTTP get I've let it return and okay with leave types all right and you notice once again task action results list leave type DPO so this is being very explicit as to what data type it is going to return now for the HTTP get with an ID What I've Done similar very similar code tasks action results leave type BTO of course it has to be async and we say viral leaf type is equal to and then we await the mediator dot send with the new request so remember that the request will get handled mediator is taking care of that part we have to make sure that we use the correct request based on what we want so in this situation the request is the get leave type detail request which is where it's getting the particular leave type with all of the includes and any other fandangles or requirements that might be there for the details we also need to give it the ID value that it will be getting because in our Handler it will rely heavily on the ID to know which record needs to be retrieved and then we return okay with the leave type now in the post we have a few more lines and it's really just me showing you how you can break it out anyways but it's not absolutely necessary because just the same way that everything could have gone in one line and we just create the new object right here I could have done that inside of this one mediator send line instead however I said VAR command is equal to new create leave type command so the post method is designed for creation all right so let me start from the tolerant backtrack got ahead of myself there public async task action results so in reality you don't necessarily have to say what the return type is it does help with the documentation when we get over the Swagger so I would put it back regardless in the situation the response would be an INT so we could say int but like I said it's not absolutely necessary so I'm going to continue without it being necessary right now and later on we'll see why it would have been a good idea to put it in so task action result post and we're doing from body and then we're using the specific detail type for the operation so remember we discussed do you get granular do you leave it General well this is a situation where we would prevent over posting by getting granular because then when they spend when they send over leave type information what we accept through this action is limited to the properties inside of the type that we specify so unlike leaf type detail or leaf type dto which has more details or more Fields the create leaf type is only designed to accept the data points that we know we absolutely need for a leaf type to be created so anything else will be ignored so when we formulate this command we said new create leave command leaf type command needs a leave type detail object so we pass in that object and then our response is relative to what the mediator returns with in this situation our response was int because that's what we had said when you create the leaf type just return its ID so that was the Handler that we designed for that kind of request so then when we return okay with the response we'll be okay with the leave ID now moving on to the put put is used for the update once again async task action results and then it by default had that ID parameter and we changed the front body parameter to be the leaf type dto so we did we had discussed from earlier that the leaf type BTO we didn't get two granular that have an update leave type deep till different from everything else that's fine so in this situation we're accepting all the possible fields that could be updated and we definitely need the ID inside of this object which is why we're retaining that as a matter of fact as it stands this ID is optional so I could actually just say I don't need an ID parameter so when you call the put you don't have to call in an ID and then this comment would actually I'll just update the comment just to have a uniformity so then task action result put and then all we're looking for is the body context with the leaf type dto remember all of our validation is happening inside of our handlers so that's even less fewer things to worry about right here when we're talking about did the ID come over does the ID exist all of those things are happening inside of our Handler between the Handler and our fluent validations actually and if anything fails on that side then this whole operation will fail anyway we look at how we handle failures later on but for now we just want to get a handle on how our controllers need to look so when we send the command to update we did not wire this up to return anything at least nothing useful right we just said unit dot value unit represented a void so we had to return something but we just said okay you're just going to return something arbitrary to say it was successful and so the HTTP response that corresponds with a a put is usually no content which is a 204. all right so we can just return that we don't have to assign the response to any variable delete looks similar delete takes an ID parameter task action results delete int ID and then we have the command which just takes the ID and then we send over the command and return no no content so if it is that you want everything to be just two lines then that's as easy as taking the command putting it in the send parameter and everything can be two lines all right so I'm just showing you the difference look at the big difference between this controller that is doing everything that this controller is doing with all of that code all right see with the edit we're doing validations here um for the delete we're doing some form of validation again all of those things are now abstracted out into other parts of the application and our controller can do exactly what it's supposed to do which is receive a request make a call to do some operation and then give you back your data all right so this is more of a review video than a lesson video I only have a few things that I want to focus on in this lesson that you probably attempted and probably had problems with and if not then kudos to you so let's just start off with the leave allocations controller really and truly this is a controller that is going to be pretty identical to our leave types control because really and truly we're only doing crowd operations here we're getting the list we're getting by ID and of course if you didn't complete it you can always just pause and go ahead and replicate as you see me going through we do the same thing for the post so you'll notice that everything that pretty much said leave request is not just saying leave allocation you could almost say that you could have created a new controller copied everything from the leaf types controller paste it in the new controller and then just replaced the leave type with leave allocation or type with the word allocation I'm just giving you tips as to how you could have done this pretty quickly and pretty effectively right because this one is pretty identical to the leaf types leave requests on the other hand has one tiny surprise and that is in the form of the update right so once again going through slowly enough um I pretty much replicated the actions from the leaf types over in leave requests so most of the content of this controller is identical to the other two with the exception of our put operation and if you notice and look very closely I would say put operations so everybody is only at one put operation One update endpoint but then in the case of the leave request we had made room for two types of updates one where it's a regular update I noticed at this time we do have the ID parameter in the put and that is because our leave request command asks for the ID and for a detail that's fine but once again these different flavors are relative to whichever style you think matches your scenario so I'm just showing you different options I'm not saying this is how it must be you have the different options use the one that is best for your situation and your project now in this situation once again we do have the ID parameter we passed over with the command and we build the leave request dto however the other update scenario would have only a change approval State status for our leave request so in that case I created a custom endpoint change approval so to get to this one you say API slash request controller approval and I really do need the ID so let me go ahead and add it to the root so it would be change approval slash the ID value as I've also updated the documentation accordingly and I need to put that ID parameter back so I took it out earlier let me put it back and build up my request object all right or my command object rather so I'm just showing you all of the considerations that need to be made but at the end of the day our controllers are slim and the benefit of this you may be saying okay so I have three lines but all of that work or in the earlier videos just so I can put three lines here why didn't I just put all the logic here which once again I completely understand because it would work but at the end of the day our code is far more testable and I don't have to test the controller to know if I would get the correct results from this endpoint instead I can go and test the Handler that is supposed to be returning those results and if the Handler works then the endpoint will work so you know it's just shifting your focus to to from being more compact to being a bit more modular and spreading the code and the responsibility across more places so that you can have a better appreciation or a better control over what each component does and how they all tie together all right so we're winding down with our API related operations and in this lesson what we want to do is seed some default data into our database the next step of course would be to test it but then it's always good to have some sample data so that we can do the read operations quite easily and effectively so to see data into our database we're going to look at how we accomplish that with Entity framework now I've done one already and I have the other two ones standby so you we can do them together but let us start off by going to the persistence project add a new folder called configurations and in there another folder called entities and then you're going to have a configuration file per entity so pretty much this configuration file allows you to put in any Entity framework related or any database related rather um configurations or defaults or any rules that you want to govern the particular table in the database but then all of the code is written in courtesy of EF core all right so let's look at the one that I have done already and that is for the leave type configuration so you can pause take this off and then we can go through the bits and pieces together so we have the leaf type configuration and then it's inheriting from I entity type configuration relative to the class type that we're dealing with which is the leave type so then everything in this basically code base is going to be relative to the leave type so once you do that you're going to end up with uh it's going to ask you to implement the interface and then that would generate this method stub for you so inside of this method stub we're going to have public void configure and then we have that instead so all of that is actually generated for you so the more the main part of it which is what you will be building or writing in would be in this Builder section so it's a builder dot has data and then we'll say leave type or create a new object so this is a method has this is a method that has open and close braces and then in there we say new leaf type and then we fill an object so this is the domain object that we're seeing your IDs one your default days to go into database is 10 and your name is vacation and then as many as you need to you can actually just comma separate each initialization of an object or instantiation of an object inside of this entire block no I haven't done the other two so I'm going to do them kind of from scratch even though but I know you probably did it already with the leave type but that's fine so for leave allocation configuration it's inheriting but there are no using statements at all so that's why you're seeing the red line so I will use control dot using Microsoft Entity framework core get the domain reference and then implement the interface which generates that method sub for me but there is nothing there for me to configure for leave allocation I don't have a requirement for leave allocation at the moment all right so I'm not seeding any leave allocation I'm not changing anything about the defaults on the table structure I'm not doing anything else so like I said this configuration file can be used for far more than just seating data and if you want a better understanding of what it is capable of you can always check out my Entity Framework or course all right so we'll do the same thing for the request and we'll just leave that there once again we don't have any leave requests that we need as defaults but we do have some default Leaf types so that's good enough for now at least we can run the API and do a get request on this table and verify that it's working so the next step after writing this code would be to go to our package manager console and we need to add migration for seeding leave types so once you do that we get a migration file that is letting us know that it will be inserting that data into the database for us Next Step as we know would be to update database okay great so this time we're not going to go to the database directly to verify that these were created what we will do is test our API so see you in the next lesson all right guys welcome back so in this lesson we're going to be looking at one testing or API and two documenting it so the key tool that encompasses both of those tasks is called Swagger so Swagger is an open source API documentation tool based on the open API standards now it comes out of the box for Net 5 API project so if we jump over to Startup and scroll a little we'll see here that we are adding the Swagger gen Library which creates that Swagger dock with an open API info so we can change out all of these things I can just say HR leave management API you know give it a title give it a version you can add other nodes to its contact description etc etc so it's a very powerful tool and like I said it comes out of the box we didn't put that there and another part that you would look at is down here are in the configure method where it says if we're in development then use Swagger and the API so if you want to you know use Swagger because I know of corporations that just use Swagger as their documentation in production then you can always just take this out of that if statement and actually use it regardless of your environment all right so you can go ahead and make that change now let us run our project so I'm just going to hit F5 with the API project as a startup project and that results in us getting this beautiful document showing us all of our potential endpoints and how they can be called you notice we still have the weather forecast we can delete that afterwards but I'm just showing you that we didn't do much all we did was set up our controllers right the code that we know we need to write but here's this beautiful document showing us everything about our API so if I click on one of these it extends and it shows me exactly what I can expect so this endpoint which is or this Behavior API slash leave allocations which is the get that gets all of the records in the leave allocations table it's going to give me a 200 success code and this is a preview of the object that we'll be getting back so once again I'm going to I always go back to details and how granular you get and what you want to display notice that in this particular detail we have the ID we have the number of these we have the leave type with its own ID the name and the default days then we have the leave type ID so you might be looking at this and saying well that's kind of redundant if I already have the leaf type object I don't have to repeat the ID here and that would be a fair statement right so you know we didn't get very granular with the leave allocation list dto in this situation we just use the leave allocation detail so we might be sending back too many details or too many fields in that response we can adjust that accordingly so let's look at leave requests leave requests would have ID the leave type the date requested and approve this true why does it have this as opposed to the one that is getting the details which has much more so Swagger is actually looking at our return Types on the particular controllers or actions rather and I'll just jump back over to the controller so you can see what I mean remember that I was saying that there is a benefit of putting the return type directly in that I action result because Swagger is actually using this to say okay this is the data type that will be returned from this action versus this data type for that action outside of that it will just make an assumption and the the return type or the schema that you might see might not be representative of what's actually being returned so that's one of the benefits a remote said there are benefits to putting the return type here that's one of them Sagar will infer the object that it needs to show the schema for in Json and that is least a better and clearer documentation for those who will be interacting with your API all right so let us run a test let's jump over to API Leaf types since those have been seeded into the database we should expect at least two records after we try it out so let's hit that end point hit try it out and execute and what I'll do is set a break point on the controller and the Handler that this operation should hit so when I hit execute it hits the control or the action rather right remember that it's going to mediator dot send and send over that request now I'm pressing F5 and then it's going to hit the next breakpoint which is the Handler so see it went from controller to Handler and where the all of the magic is really happening inside of the Handler so in the Handler we have a repository and or mapper they're both initialized injected and then in the Handler we carry out the query and then we return the dto versions of the data all right so I'm just going to hit F5 again and allow it to complete its operation and then Swagger then shows us the data coming back from the database there we go name vacation default this id1 etc etc etc and in the same way if I go to the get and I try it out then it allows me to pass in the ID so I'm going to pass in id1 execute and then it brings me the one record with the ID one now Swagger allows us to do all of the crude operations at least test every endpoint that we have laid out so let us try another one where we're going to create so notice the difference between this schema and the schema being returned by the detail by the gets right this one has the ID the name the default this this one only has name and default days that is because of course we're using a different detail with limited scope so for the name I'm not going to change anything here um I'm actually just going to put leave this default there all right so we're setting up our UI project in this new module and what we're going to be using for our UI project is the asp.net core web app MVC so our client application or UI could easily have been built with any technology that is capable of consuming a restful API so we have our API that we already set up but when we're going to be creating this client we could have used angular view reactor laravel or you know Blazer any one of these but I'm really going to stick to the MVC because it's rare that you actually see an MVC app being the consumer of an API It's usually the all-in-one anyway that and the original project was already built in MVC so we're going to kind of keep that MVC feel to it no problem but then the underlying architecture has already been gutted and set up so we'll go ahead you can just search MVC and remember that it's asp.net core web app not the asp.net web application all right so you hit next you give it the name which in which case we're calling it hr.leavemanagement.mvc and we are using a.net 5 project you can also enable Razer runtime compilation while you're here and then you can just hit create now once that's done you're going to end up with this project which is the standard MVC template the boilerplate for a standard MVC application for for.net core you'll see that it looks a lot like our API project except that it has a few more folders like views and models you know MVC model view controller and then we have the same startup file the same project program.cs file the app settings all of those things are kind of commonplace and we have the www root folder which has all of our static assets so if you're already familiar with MVC where you have no problem but I will try my best to be best to be as detailed as possible with all the changes and the code that needs to be written and how everything ties together so when we come back we look at how we can start integrating our API into our clients all right so we're back and our task today is to set up our client application to consume our API so we already created our NBC application and we have our API documentation in the form of this Swagger dock so we'll be using nswag to help us to generate literally generate the code that would help us to consume this API and between Swagger and in swag you'll see that in a few clicks in a few minutes we will have all the code or at least most of the code needed to actually establish communication between the client and the API so step one bring up your Swagger documentation and then you can head over to the Json file that it generates by clicking this link which will bring up this Json file which is basically powering this display that we're seeing here so what the next thing I want you to do is go to Google or Bing and find the GitHub page for nswag Studio then you can download and install that and it's well documented but we'll be going through exactly what you need to do to get it up and running so you can just download and install it and once you have done that you'll be greeted with this beautiful interface so there are a few things that you want to do to get started with this procedure number one you want to make sure that the runtime is correct so by default I think it may go to net core 2-1 we're using net five so you can just go ahead and change that and then the specification URL needs to be the URL to the Json file coming from Swagger so you can just copy that from the browser and paste it there click create local copy and then you'll see that documentation appear below no with all of that done and just to note that in swag does support other types of client applications meaning typescript if you if you were using view or react or one of those JavaScript Frameworks then you could just as easily generate code using in swag for those types of Frameworks however we are sticking to the c-sharp client so you'll just tick that and you get that new tab and then there are a few settings here let me just go to the top there are a few things here that we want to make sure are in place number one set up the namespace so for namespace I have hr.leavemanagement.mvc.services that's the namespace I intend to have all the code generated into there are other things that may be ticked already but I'll just go through and make sure that we set up the correct one so use the base URL for the request you want to make sure that is ticked as well as generates the base URL property must be defined on the base class all right uh you want to make sure that you have the inject HTTP client via Constructor ticked and generate interfaces for client classes scrolling on I think most of these are already there by default you want to make sure that you have the generate detail types ticked and narrow to the end we want to also ensure uh then we get to the end actually because I think everything else here will be already filled in by default so I'm not going to spend too much time on things that are already there and not are and that are not absolutely necessary so anything that I've pointed out just make sure those are in place you can leave everything else and then at the end of it you want to put in the output file path so you can just go to your project right click on the project uh go to visual studio sorry right click on the project and go to open in Explorer take that URL or that path and paste it here but we're putting Services slash base slash clientservice.cs so after you've done all of that you can go ahead and hit generate files and it shouldn't take very long to generate those files and then when that is done you can jump over to visual studio and go to your services base and service client class I have some files here that we're going to discuss later on but let's just focus on the servant service client file so we have this client file that gets generated and it gives us an interface and the implementation of the interface out of the box right lots of documentation and annotations don't really have to worry about too many of those things but at the end of the day it generated about 1700 lines of code at least in my book So based on the size of your API you may get more you may get fewer but the point is that all of this was done for us so we can focus on more important things right so we want to work smarter not harder another important thing to note is that Within work anytime that documentation changes meaning somebody made a change to the API Swagger as a result got updated you know the endpoint requirements changed whatever it is that change you can always just state that you're put into Instagram and regenerate this file so you don't have to get that that reduces the back and forth especially in an agile environment where changes are inevitable and Rapid so you can always just keep up the pace with regenerating this client and changing the code around it as necessary now I did mention that I have a few other files and while we will get into the details of them I'm just going to show you so I have contracts and in the contracts I have a contract file or an interface per endpoint type that I know I'll be interacting with and I also have a service implementation file for each contract I haven't started filling those in but I'm just giving you an idea of what these additional files are in the base file base folder I also have an API response and there are more files that will go into the base just so that we can have that extensibility but for now you don't have to worry about it the next thing that you may want to do though is set up Newton soft so you're probably getting an error anywhere that the word Newton soft is being referenced in this file so you can always go to new gets and then you would want to look for Newton's soft sorry microsoft.asp netcore.mvc.newtonsoft.json so you can go ahead and install that do a fresh build and those errors should disappear next in our startup class we want to register our HTTP client so you say in the configure Services we would say Services dot add client and we pass in I client and client those two are coming from our generated file and then we want to pass it the Base address so we'll just say CL or you could use client you know that's a Lambda expression dot Base address is equal to new Yuri and then we want the URL to the actual API so to find that URL to the API what you can do is go to the API project expand properties and launch settings and then you'll see that SSL Port so it's basically https localhost colon for for in my case four four three two seven in your case it might be different right so https localhost and that SSL Port as you see it in your launch settings so with that done we've actually set up the client or at least the foundation for the client so the contracts and the service definitions that we have here and we will be fleshing out when we come back are relative to the specific operations needed per call because when we call say get all leave types how are we going to display the leaf types in our client application we still need to have models we still need to deserialize it from Json because you know rest apis they are sending and receiving Json so we'll need to convert from Json into some type that or client application can appreciate and then we can allow the user to interact with it accordingly so when we come back we look at all of those other coding activities that we need to put in around our client so now we're going to be creating or going through some of the supporting files and functions that we're going to put in place before we continue with building out our client application so these are really one-time operations that we're going to be going through and I'll explain why they are helpful not necessarily necessary but at least helpful so let's start off with our third-party libraries in new gets we're going to go and get Auto mapper and we're going to get local storage by Julian Hansen's all right so that will help us later on we're not necessarily going to use it right now but you can just go ahead and get it from now so that we can just set everything up once and for all we're getting both Auto mapper and auto mapper extensions and we already have the Newton soft so with all of that installed in the startup we're going to make sure that we add the auto mapper now you're probably wondering okay why am I adding Auto mapper again after we probably did it already in the application so we had set up the services registration in our application layer and we had added automaper so you're probably wondering okay just like with the API when we just called configure application Services why don't we configure application services in the client well the reality is that the client really doesn't know anything about anything else in this project right so it's its own project imagine if we were using say a view or an angular application it would be the same thing there will be no yeah apart from the fact that there would be no Auto map but the fact is that there would be no core or infrastructure references it barely even references the API it just knows that an API should be found at an address and that is the Assumption it makes so with that said that is why we're not referencing any of the other libraries inside of this client MVC application it's Standalone and all it does is reach out to an endpoint and expect a certain result afterwards which will be the API call which we have configured here so we're adding automaper individually to this project and once again that's because when we're getting back to detail we might have to massage it a bit before we display to the user or interact with it in any way shape or form so we add Auto mapper and I have already gone ahead and added that but you don't have to worry about that line we'll be going through these three lines in detail in a few so just go ahead add Auto mapper and then the next few things that we have to put in place would be to create a custom response type so our response type here would be used when we talk to the API and the API response it could be with the command response it could be with or or base command response rather it could be with the validation errors whatever it is we don't know remember we're only interacting with an API so we're either expecting good stuff to come back or some form of exception or some form of bad response we don't know so we're creating our own generic response type on the client which will be capable of getting a message it will be capable of getting validation errors in the form of a string it will know if it was successful and it would get back some object so I'm calling it t because we don't know what it could be it could be an object with the you know we return the object in some of the create it could be an integer with just ID we don't know of course it would be prudent of us to kind of backtrack and standardize all of those things for educational purposes we would have gone through different scenarios but at least going into the more Enterprise setting would want to standardize that so that we can definitely know what to expect for each scenario so that is our response step from the client all right so moving on in the next the next file that we have that we want to look at is iclient so in the base folder we have Iceland and we have clients and you're probably saying okay but we see I client and client before and if you're saying that then you are correct in our service clients that was generated we do have high client and we do have clients but then we just want to kind of create a little extension of that so that we don't have to dig too deeply to get to certain things so one you'd notice that this is a partial right so the cool thing about a partial is that it means that you can have multiple versions of the same class of course they're all going to work together but then you can have multiple files with the same name the same class name or interface name and it's like they all merge at the time at runtime so it's pretty cool if you've never interacted with partials but we have the partial being generated for us already so we're just going to create our own partial implement Temptation or our own partial I client interface which just has access to the HTTP client all right so in service client we have that HTTP client uh you know it's very deep within and it's probably not very accessible so we're just creating a public version of that and then in the implementation which is public partial class client in the inheriting sorry from Iceland we just have that public up a property which is getting or returning that private property from the service client so there's our private HTTP client so that means this allows us not to actually you know interact with the HTTP client in case we wanted to do anything to it like later on when we're doing security we're going to want to interact with it to put on headers before it sends off information so you'll see that in a few now one point to note with the Iceland and the client you want to make sure that they're in the same name space as the service service client all right so actually when I was doing this I did not have the dot base because I gave it MVC dot Services that's the namespace I give to nswag to generate this file at even though it's going in the base folder and then I client was automatically created with the namespace.base so you have two options you could either change this one to that base and then make sure that in swag knows that it the namespace should be that base or you can just make sure that this is Services because if they're not in the same namespace then they won't see each other as partials so you can just take note of that when you're doing it if you're getting any errors that you can't figure out why you're getting them now we're going to go back to our contracts folder and in there you'd see that I have a file called ilocal storage service now a little background for what the local storage service is for we will be implementing authentication using Json web tokens or JWT for short now after a token has been issued to the application application here being the client application we need a way to store it in between operations so you know you log in and then while you're logged in you're probably looking at your leave you're probably you know doing a number of things anybody can be doing anything at any point in the system but we are going to require authentication for you to be able to complete certain things so a token definitely needs to be present like I said we'll be adding that later on but I want us to set up this at least the ilocal service I local storage service from now because it will be needed for some other base setup that we want to do now so after you get that local storage library from nuget we are just going to create an interface where we can abstract out some of the operations um into our own methods so we want clear storage exists get storage value and a set storage value and it's really just a value keep here so we're just going to give it a key and then a value so you can use this to store little bits of information of course you don't want to store anything too sensitive inside of the local storage because then it can open up your application for vulnerabilities but that is its purpose so after you set up this interface you can go ahead and set up the implementation in the services folder so we have local storage service inheriting from ilocal storage and we have a field of type local storage which comes to us from the library given to us by hansons.net and here in the Constructor we're just setting up like a little config and then initializing storage so our configure says new local storage configuration Auto load and auto save are true and then the file name I just gave it a name that is indicative of the application that it belongs to so you can go ahead and do that and then storage is equal to new local storage now the methods are fairly straightforward in the clear storage we just have the list of keys that we want to clear from Storage so this would come in handy when somebody is probably logging out and you want to remove the references to the tokens and whatever else you would have stored you can just go ahead and pass in all the keys and it will just remove them for you you have the set storage value where we pass in the key and whatever value and then it will store it now this is T yes it can take like an object or a string whatever data type but it will parse it down into some form of well stored value and then storage dot persist basically says just keep it make sure you're paying attention to this get storage value basically just returns whatever it is based on the key that is requested and then we can always check if it exists right so passing the key and it will return storage axis which is just a Boolean yes it exists or no it doesn't now one step that I would have overlooked was to add this to the startup file so we have to say Services dot add Singleton this time because we don't need multiple instances of our local storage that would actually be a pretty bad idea right so we just want one instance of the local storage to persist for the entire user the user runtime or the usage of this client application and we're just passing in the Ilocos storage Service as well as the local storage service now in our base HTTP service which is living in the base folder in our services we're just going to be setting up some base operations that want every service to be able to do so one where we have the fields for Ilocos storage uh Storage storage service and our clients which we initialize using our Constructor we're familiar with that we're just injecting them in and then later down we have two methods we have one where we convert API exceptions all right so API exception is actually coming from our service client code generation because in looking at the endpoint looking at what to expect it realized that we could get custom exceptions with status code and response and other things right so we have access to that base type but then we probably want to convert it into the response if it ever comes over so we can say if the status code of the API exception is 400 then we say validation errors have occurred because that was the bad request right if it's 404 then we say message the item not be phoned and then otherwise if it's a 500 you say something went wrong and as many error codes as we would have you know be we know that we would be able to get back from the API we can always set them up here and have customized at least to some extent customize messages per error type right the next method would be to add the bearer token so protected void add Bearer token allows us to say if the local storage has some value with the word token so I'm just once again laying the laying the groundwork here right where we're not quite ready for this one I'm just putting it there and we'll discuss it in detail later on but this method allows you to add the bearer token to the client.http client default header request authorization right so all of this code is basically how you get access to the authorization headers in any HTTP um clients communication with a restful API and what we'll be doing is adding a new authentication header value let me just break line here so it's more clear so we're adding a new authentication header value with the name Bearer and we're pulling it from local storage get storage value of type string with that key all right so that is how we'll be getting the tokens to send with our HTTP requests but we're not quite ready to discuss this in detail but you can write in the code from now once again all of this is groundwork now when we're going to be looking at our custom I don't like calling them custom but our extensions of the the different features or the different kinds of interactions that we're going to be having with the API like all of the leaf type interactions all of the leave requests and allocation interactions we have abstracted them into their own contracts and then all of them will be interacting with the base HTTP service anyway because when we secure our app they will need certain base functionality and for General interaction all right so when we come back and we start looking at setting up the leaf type because that's always the easiest one right that one is fairly straightforward so we're going to start off with that one and then we'll look at how we tie everything together all right welcome back we're going to start looking at the leaf type service requirements but before we get into the contract and the service implementation in the UI project I want us to do some housekeeping things with the handlers and the API and I'll explain of course as we go along why these are beneficial before we move forward so to start let's just jump over to the create leave type command Handler and if you need a refresher that is in the the application project under the core folder all right so what I would encourage you to do one is to standardize what is being returned so at all points we want to probably have the base command response remember that the base command response allows us to pass back the success flag the ID of the new record as well as a message right so you want to refactor your Handler code I'll just leave this on the screen long enough that you can pause and refactor accordingly where if the validation fails then the response success is false then we'll have a message and we put in all the validation errors and then we have else if it is okay then we have the true the message and we return the ID with the response object of course if we're updating that to return base command response that means that our request needs to also return that so you can just go ahead and update the leave type command to have I request returning base command response so that sums up the changes that we need in the Handler as well as the command class now moving on from that let's jump over to the API now back when we were discussing the API we also mentioned why it is a good idea in the task action results to also include the data type being returned and we saw in the Swagger documentation that you know for the ones that had a return type the documentation actually clearly stated what would be returned now that we have adjusted the return type for our create command Handler let us also adjust the action results return type for the with the base command response all right because then when we do that we get the response we return okay with that response all right so that will now enhance our documentation and then I'm going to show you another thing that makes it even better in terms of what the documentation being up to date and being That explicit helps us to do now one more thing before we move ahead I want you to right click on your test project and run tests so just in case you weren't convinced about why unit tests are important if you run the tests you'll probably get all failures for the tests that were to check if the if the validation or the valid leave type or invalid leave type were added successfully why are they failing well we just made a refactor so we just changed something in our code and our test was checking for one thing and obviously what we changed would break that test now if you go back to your test remember that we said the result of the add operation should be of type ins so once again this is a great way to see we're refactoring your code would actually modify things right so now the valid test would have said should be leave type ins we are going to change that to should be base command response now the invalid one was counting on a validation exception being thrown which was the case before or factor just now so we actually need to adjust this test to now reflect that there is no exception one and that we are just doing the same kind of operation where we're just calling waiting for a result because that is what our new code is doing right so we're calling waiting for a result and the result should be off the type base command response and the count should be three so if we rerun those tests then we see that we have successful tests all around so once again unit has helped us to keep us helps to keep us in check with our refactors and our code changes in such a big project so now that we've modified our API we need to regenerate the code with the service client and in addition to just regenerating there are a few changes that I want to point out with the settings as you do that so once again go ahead and get that Json link if you didn't have it up already and then in the end swag interface we're going to paste it and we're going to recreate the local copy so we have to do that step every single time whether you had it there or not because whatever it sees in the Json is what it is going to use when it's generating the code so I'm pointing that up because before the post method that we just modified only had a return type of 200 with maybe an INT now you'll see that it has other return types all right so the inference from that for the end swag studio is that it needs to compensate for the fact that it should expect a return type of Base command response so we're going to have to repeat the same things if you have it open already that's fine but if not we can go through it again hr.leavemanagement.mvc.services.base I'm putting on the base this time missed it off the first time I want to ensure that we're generating the exception classes inject HTTP client via instructor and generate interfaces for client access and we want to wrap the detail exceptions in Swagger exception instance we want to generate the dtos but one thing that if you had ticked before I would love for you to untick is this one about the use base URL for the request so initially we are ticked it you can untick it reason being in the service client code that you have up now you'll see that there's a base URL field in there and it's waiting for a string so we're actually kind of bypassed the need to put the string in that code because we had registered our HTTP client with its Base address so we don't need that use base URL for request anymore all right so you can just untick that one and go ahead and make sure everything else is ticked accordingly and once you've done that of course you point it to the output path and then you generate files so once you do that that service client CS file will be regenerated and updated to now expect the new return type or types if you refactored more than one things whatever it is that is new in your API will be reflected in the documentation and as a result reflected in your new service plan class so now that we've completed the groundwork with our handlers and our API let's jump back to our UI so I'm in the startup class and we can see that I've uncommented the I leave type service leave type service line we will uncomment others in due time but you can just start with that one uncomment it and let us look at the implementations before that though I want to point out that we do have the mapping profile so I created the mapping profile which it follows the same procedure as we're used to from our application layer where we inherit from profile courtesy of Auto mapper and then we start putting in these profile map configurations I also have created some view models and I'm going to actually start with the view models before we look at the leave service implementation and interface so if we just jump over to that I have created in our models folder leaf type VM I just put everything in one file this time around right so in the leaf type VM you'll see that I have that which represents the VM that has all Fields but it only has the ID and then I have create leave type VM where we have the name and the default days so leave type VM inherits from create leave type VM so we always looked at how can we reduce repetition between the VMS and once again it depends on how granular you want to get in terms of the data or the data points rather that you are putting into your view models so here leave type VM has ID and inherits all the other fields from create and create does not have that ID and we already discussed it from the detail level why that is done that way so once again from the mapping profile I can map like to like between the view model native to the to the UI application or the UI and the dto courtesy of our I service client file or service Clan file sorry where we have all the details kind of being made a reference to in that file so you can go ahead and replicate that kind of mapping and those models now let's jump over to where I leave type service so this interface sits in contracts and it basically implements all of the crude functions that we know are native or unique to the eye leaf type operations or the leaf type operations so we have the get Leaf types which is returning a list of leaf type VM the one that gets the detail returning the same VM we have task response in so we already looked at the response class so here we actually expect that response relative to the fact that we're getting that base response from the command that is creating our leaf type so our task is going to return a response button interior just represents the ID value that is coming back because that's what we really really want right so response relative to the type of int create leave type and we're passing in that leaf type VM we also have the task to update and a task to delete so after we've set up all of these in the interface as we've seen before once you have a contract you have to have the implementation so over in the implementation which I just put in the services folder we have the leave type service so let us go through this one together so this is inheriting from the base HTTP service which we went through together and the eye leaf type service at that point is going to tell you all you need to do the implementation no problem you go ahead and let it Implement all of the methods required so inside of this leaf type service we have the local storage the eye mapper and I client being injected so all of those are injected and initialized accordingly we also have to pass over to our base and base here being the base HTTP service the HTTP client as well as the local storage service you've seen that already so you have to set all of those things in place I want to stop there really for this segment when we come back we will look at the different methods that were implemented I have some code there already but that's fine we'll go through it in detail when we come back but these are your methods being inherited from the eye leaf type service and they're all put there waiting to be implemented so we'll go through that as well as our controllers and our views in the next lesson in this lesson we're going to be walking through our controllers and Views and the general user interface and how we let our application interact with the API for all the crud operations but before we get there I have some corrections that we need to make to our interface and the implementation for our leaf type service so Corrections would include updating the return types for the update and delete I kind of got overzealous of the copying and pasting and in the previous lesson you'd have probably copied over the incorrect implementations or the incorrect prototypes for these methods so you can go ahead and update these accordingly where they are all supposed to be returning the same task response relative to the type int and for the update and the delete update is going to take an INT ID parameter and the leaf type VM and the delete is going to take that int ID parameter so you can go ahead and make those changes and of course update the implementations inside of the the leaf type service file now in order to start making the user interface of course we have to put the underlying implementation and then wire up the code and everything so we'll start off with the very simple ones which would be the get leaf type or the get Leaf types which of the list and the get leaf type details which would be the one right so let us look at the implementations for those two and they're pretty simple all we're doing is initializing a variable I'm calling in the leaf type so I'm calling it varleaf types equals await client so this client is not the HTTP client that's being injected in but the clients coming from our base HTTP service right granted it would almost be the same thing because the only reason we have this one is so that we can pass it over to the base all right but let's just stick to it so underscore client represents the base HTTP service client and that's what we're using so I wait underscore client dot leave types all async all right so that is giving us access to all of the methods that were generated for us in the service client thanks to nswag so you'll see Leaf types or Leaf types delete get post async based on how you name the methods in your API controller you may see slightly different names but I just talked to a particular naming convention for standard API development and I'm just getting these so I think it's clear enough that this one is getting all the other one is getting just one get Etc either way the parameters can always be your guide so VAR Leaf types is equal to await all the leaf types and then we return mapper.map list leaf type VM and the leaf types all right so that's why this is returning that list of leaf type VM because this would be returning the list or collection of leaf type dtos and we're just mapping them to our local leaf type VM so we already looked at the mapper and the configuration for that no outside of that for the details what we're doing here is getting only one so we're seeing wire leaf type is equal to 08 client dot Leaf types get async and the get takes a parameter off int ID and then likewise we're returning a mapped version to leave type VM of the sleeve type now let's go to one of the more complicated ones and let's start with the delete leaf type now delete leaf type only needs the ID it only needs ID because the API parameter only needs the ID so we're doing a trend catching the situation where we're going to say await client dot leave types delete async passing in that ID and then we return a new response of type int where the success is true all right so if that was not successful then that's why we catch and then we convert our API that would have our API exception rather that would have been coming back into the response with the appropriate information all right so that's pretty much it for the delete and then the update actually looks very similar to that except we're taking ID and the leave type in as type leaf type VM then I'm going to do a mapping to convert it from leaf type VM into the leaf type dto before we then send it over now the thing about this Leaf types put a sink if you hover over it you'll see that it takes an ID of type string mine generated string I found it surprising but I just said let me work with it instead of trying to work around it if yours takes ins then that's fine you don't have to do this ID dot to string but in my case it takes strings so no problem I'm taking the int ID I'm just converting it to string and I'm also passing over that leaf type detail that I just converted then if everything was successful we just return a response with success being equal to True once again it's in a track catch so any exception would be caught now with the create I put in a bit more so I started or you would have seen a preview of this but let me walk you through what this code is doing this time so once again it's returning the response with type int it's taking create leaf type VM as its parameter and well it's really the same bit of code but just with a few more plots and twists to it so here I'm seeing create leaf type dto and I'm doing the mapping and then I'm saying get me the response from the post so the reason I have to do this is remember that we updated our API call to return base command response the other ones are returning no content right so they're that's why they're only tasks but in the case of the create we're actually getting feedback after the call so we're getting API response which is base command response so service client actually generated this class for us to mimic the base command response coming over from the API so remember at this point we still don't know anything about API we're not interacting with the actual based response implementation that we did all the way up in our application layer all of this is being done right here in the client app so base command response comments back after we make a post attempt and remember that a post attempt even if it fails it's not necessarily a failure because it could have failed because of validation reasons but would still be getting back at 200 uh response right so the try catch and just to backtrack a bit the try catch here is really that if they the service client is set up in a way that if the response is not a 200 then it sees it as an exception which is why we do that conversion now in the case of the the create we could have gotten a 200 response with this base command response but then it's not successful so we're getting back okay HTTP wise but the operation itself was not successful so the engine is telling us that it was not successful we wrote that engine so we know about that right but in in the case that you are consuming a third-party API that's at this point they would have had to make it clear to you that you could get a 200 but you always have to check this flag if it's true or false so in this case if it is successful then we outfit our response that's our local response of type int we outfit the data with the ID remember we talked about that returning the ID of the newly created record and then the success is true so locally we know that our attempt to create was indeed successful otherwise we're now going to get all of the errors that would have been packaged in that base command response with those with the you know validation errors and then we're putting them into our local response and piling them up and then we're returning that response so it was true or false were returning that response and once again we do catch any exceptions that would have been thrown so now that we have a walkthrough of what our service implementation code looks like and of course this is still privy to changes in an agile environment you may do it one way and then change it down the road because of something else that's fine but for now that's what we have so the next step would be to start creating our controllers and the controller that we're starting with would be of course for leaf types so you can go ahead and right click controllers click add controller and I'm going to just do an MVC controller with read write actions go ahead and add it and we're going to be calling it Leaf types controller so now that the controller has been created the first order of business would be to set up the injection so we want to inject our eye leaf type service and we can of course go ahead and add any missing references so I leave type service is now in our controller let us start off with the easy I'm going to say the easiest pages to get up and running and we can start off with the index page so easy way to create the index page you can just right click click add View and we want a razor view index we want the list template and then it should be a list relative to the type leaf type VM so you can go ahead and add that once you've done that you'll get that view all right so it's nice and simple and if you're used to MVC then this is no real task for you so you know what this is and because we're not using an EF core domain object certain things we'll have to wire up manually like this section where it's asking for the primary key so I would say item dot ID so that's why we use the leave type VM which has all the fields as opposed to the create or the other ones because we definitely need the ID for this list so you can go ahead and update those links so that edits the details and the delete know where to get the ID from when we need to navigate if you want to spruce up a user interface from now you can also remove the ID Fields because you and I know that we don't necessarily need those in the daily operations of displaying data know that the interface is created of course we need to let the interface know where it's getting its data from so this data call is going to be pretty simple where all we're going to see is VAR model is equal to a weight uh the leaf type repository get Leaf types which is what we just looked at the implementation for so it's calling get Leaf types which then calls the API and Returns the mapped version so once again we're promoting slim controllers here because we don't want to be doing all of that logic here you know doing the API call doing the mapping and then returning the view we want to farm that out to somewhere else so the controller just knows call this method get the data and then carry on with life this red line is because we need to make this method an action result that is a task and async right so if you want you can actually just go through and make all of these because they're all going to be making asynchronous calls so just to reduce the likelihood of getting these errors just go ahead and change everything to an async task of action result and then that is it for the index so let us take this first spin before I do let me go to the layout and add a URL for it so I'm just adding a new menu nav item that says asp-controller Leaf types SP action is index and it's leave type so let's run and see I'm sorry before you run before you run I failed to mention that we need to let both the client and the API run simultaneously so what you need to do is right click the solution go to properties and then you would go to Startup project and change it to multiple startup projects so we need the API to have start and we need MVC to also have start if you want you could make this start without debugging so it takes an even shorter time to start up so you can just go ahead and click Start so now our app is up it's running and all we need to do now is jump over to leave types and there is our data that is data coming directly from our database well we don't know we don't care at this point where it's coming from we just know we're calling an API asking it for the data and then we're displaying it here so everything is happening out of the box right of course in the background as the API developers we know all the work that we put in with the handlers and everything so we know where the data is coming from but our client app doesn't know all right so next up we want to be able to create so we need to create our scaffold that creates View to do that once again all we have to do is go to view right click add view razor View and then we want to create template and the model here would be the create leave type VM and then you go ahead and add that so once you have added The View when you get the physical file the code that we need to write here is well it's twofold so one for the get we don't need any code because we're only loading the form right so it's already it's already created that form knowing that it should be relative to the fields that are here so we have the field for the name we have the field for the default days we don't need to do anything else unless you have something special that's fine but at the basic level nothing else is required however on post that is where the magic needs to happen so what we need to do now is to await our call to the create leave type operation and well before we even get there we need to make sure that we're looking at the correct data type right so I'm going to call this create leaf type VM and leave type go ahead and include any missing references so create leaf type VM leave type so we're going to try to get a response from the leaftech repository dot create leave type and then if our operation is successful then we can redirect to index all right so look at this now if we when we do this call if it was a success then we can operate like it was a success what happens when it failed so when it fails we would want to of course add our validation errors to the user interface so the errors would have come back with the response so we can say model state DOT add model error response validation errors and at the end of all of this we just return the view so we're going to modify the catch to not return the view as a matter of fact I'm going to modify the catch to catch an actual exception and then we can add that exception so this is at your description of course this depends on the experience that you want your user to have because you may not necessarily want them to see the details of this exception you could probably just put in something that says something went wrong please contact your administrator but at the end of this operation you do want to return the view and you can even put back the leave type data that was just submitted into the view so that it has whatever to display to the user so let us take that one for a spin all right so we can run the application jump over to our create and I'm going to create compassionate leave with the default number of days as 10 but let's say I made a mistake and I put in too many zeros and then I click create you see here that we're getting back our validation message and I'm sure this message looks very familiar I haven't typed this message since I have been building out this UI app this is coming directly from the API so this is just to show you how the information traveled from the API and how we could display to the user that the API says this is illegal now you have two options when it comes to validation you could one rely on the API for all of your validation and your messages and so on but then the thing is that you at some apis charge per call right so in the situation where you're probably building on top of an API that you know you don't want too much traffic or the the API users tell you they don't want too much traffic or you're limited or something what you could do is use the documentation from the API and enforce a validation from the client side so this message is coming directly from the API sure but then that means an API call was made some process was done and it shot it back with that message all of that could have been avoided if I read through the documentation as the client application developer and set up my own validation rules from the client side so then this would never even get to the API call until this is valid by the client standards now their mixed you know based on your situation you will have to do it one way or the other but for now we let the API do the validation and then and I think it's always good to build in validation in the API because that's the last line of defense before or at least in the handlers rather that's the last line of defense before it gets to your database so right there you want to make sure only valid stuff gets the database you could however encourage your API consumers to follow the validation rules so compassionate leave default number of days 10 continue the creation and look at that we have a brand new leaf type so the creation worked and then it loaded reloaded the index page and we're back here don't mind the ID some experimentation went on in the back end but at least we are confident that this is working now somebody came back and said um compassionately should actually be 15 days so now we need to go ahead and edit it now the first step is to actually create the view so right click view add view edit and we know that we're using the edit and the leave type VM and then once you have all of that in place you can go ahead and add and then in the edits you notice just like with the create we have two methods we have the post and we have the gets now in the get it means that it has to get the record to be edited well how do we get that record we already know how to get a list of Records we haven't looked at getting one record just yet but whatever code we have to write to get the one record here is pretty much the same code we have to write to get the one record here so what we're going to do is say VAR model is equal to a weight leave type repository dot get leave type details so details would bring back all the fields that are needed for an edit operation the ID um the you know the fields all the fields the name of names of the fields are eluding right now but we're getting back all of the details for the leaf type that is about to be edited then we're returning The View with that data so while I've done this here for the edit I'm really just going to do it again for the details because it's the same thing details we get the details we get the ID pass it along and then we return The View with that data all right so we go ahead and do that edit um for the get and then for the Post it's going to look a bit similar to our create except our parameters should have the int ID and leaf type VM all right so ID leave type VM and then we're trying to get a response from our update leave type and then we pass in the ID and the object to be edited and if it was successful then we return to the index otherwise we basically just daisy chain all of the validation errors just like we did with the create and then we return The View with the data that was submitted so let's test out the edit operation and after that you can see that there are some fields that we don't need for instance we definitely don't need to display the ID in this fashion in an editable fashion to the user that's not even going to work our API would reject that all together the database would reject it right um the name the default number of days that's what we said we needed to change to 15 and you know I'm just curious to see what exactly is going to happen if I attempt this if I click save all right so I'm getting this message that value cannot be null value cannot be no okay let me change this back to 10 and let me click save all right so that worked now let me revisit what that message meant um if the data is invalid do remember that our Handler that is dealing with the update right now it was or at least originally was designed to throw the validation exception when the day data was invalid so jumping back over to that Handler just so you can see what I meant we didn't return anything it was just the unit right which we explained was just something to say everything is okay um but then when the validation result was invalid we threw a new validation exception now this validation exception has not been handled we haven't written any real code to handle what happens when our Handler throws an exception how the API deals with it and how everything else comes down so between the hand letter and the exception the API not having global error handling to know what kind of response to send back and then the service client not being able to Fathom what kind of response this is then we're getting this kind of error so technically you wouldn't necessarily well you wouldn't at all want to use it to see an error like this this is actually the error coming back from that whole try catch and the exception message being thrown back into the model State validation he wouldn't necessarily want to use it to see that but later on when we look at Global exception handling we'll see how we can better or provide better feedback when exceptions are thrown through the Handler or through the API all the way back to the user interface without us having to compensate for too many scenarios all right but for now we actually see that the validation is working to some extent it is failing because if I put a breakpoint here in this Handler and then I click save again oh I'm not in debug mode all right we can do that later but you can try that just put a breakpoint inside of the Handler try that save you'll see that it hits the validation is not their um sorry validation is false and then it will throw the exception back and if you step through and follow it on the line You'll see why all of this just amongst this very vague message however we do see that the edit is working properly and next up and we already looked at the details so you can go ahead and generate the details view I have mine already and you'll see that between the code that we just put in the controller and you're generating The View you can view the details so the next one would be delete now for the delete usually stunning a two-fold step in MVC applications right so usually you get the record and show it to the user like in a details view and say are you sure you want to remove this record and then they would say yes and then it basically submits a form so this is a very secure way or the better way to do a delete let it submit the form supported by the anti-forger token and it would carry out that Elite operation now what I would do or there are a number of ways to approach this but what I have done multiple times is instead of using both the get and the post I just have the post right so this is what my delete method looks like and if you look at it you see that it looks very much like everything else like the editor and the create rather so we try we get the response if it's so successful then we redirect to the index page and then I'm just returning a bad request so page the application will just feel but we'll look at how to handle that later on when we look at our UI modifications for now however on the index page what I would do is instead of having this Action Link I would actually wrap these in a form once again there are many ways to do this because some people have the form going through and through some people have one form and use JavaScript to say when you click the delete button then delete the form but right now I'm just going to keep it simple enough to get through this so this is a delete button all right so I didn't want to bore you with my typing so I went ahead and finished it up so our form looks something like this we have form SP Dash action delete SP Dash root ID is item.id and using that at sign for raise reviews and method is equal to post so between these three we'll know that it should Target the post method of the name action and passing that ID so then it knows post delete with that ID and then what we need to do is put in that button so button type submit and I gave it the class BTN BTN dashlink so it looks like the other two links so it looks uniform nobody would ever know that it's a button unless they really go into the code to see and then on click we are returning a confirm window are you sure you want to delete and then we pass in the word delete so let's take a look at what this renders all right so this is what we get it's not quite lined up we can fix that later on but the point is that we're getting that delete button so I have a very random one here I think somebody was trying to spoof the system and they entered that so that's fine let us delete it are you sure you want to delete this record okay and then you see everything happened the record is no longer there so that means our delete operation worked successfully and with that done we have just completed crud for our Leaf types via our user interface all right so when we come back we look at how we can complete the other specific operations with the leave request and the leave allocations hey guys welcome back in this lesson we're going to be talking about authentication now the next logical step following or setting up the leaf type UI would have been to set up the leave allocation and the leave request uis but then the spoken that plan is the fact that in order to allocate leave or request leave we need users or employees so the only way we can get the employees to use the system is if they have logged in and we know who they are and that is why authentication needs to come before those other two features so I've kind of gone ahead and implemented it because there's quite a bit of code to write and I don't want to bore you with watching me type so of course I'm going to go through it very slowly so that you can pause replicate and explain everything that is there that needs to be understood now outside of that I have up Swagger where I I have implemented JWT authentication so I just have it up so you can get a preview of what JWT authentication really is in case you're not very familiar with it so letters JW and T are short for Json web tokens and what they are is just like a package just a flat string that is encoded but within this encoded string are what you call bits of information or claims that allows the decode and know who the user is now JWT is widely used in the API fraternity as the standard for security because it allows for stateless authentication meaning when you log in you're not really logging into an API you're accessing the API but if it is locked down or protected and you authenticate on the API they basically identify who you are and then send this token with all the information about who you are so the client application now needs to say anytime I am using the client application and I request data from the API it needs to include this token with my information so that every time the API gets called when it sees this token it will decode it verify that you know this person is valid and then be able to execute on the request so just a quick demonstration here I'm going to try and log in so I've already modified Swagger I've already modified the API with the login and registration endpoints and we're going to go through that but I have also put in some sample users and I'm just going to go ahead and show what the token looks like so I'm executing a login request with one of my users and you see here it's returning a 200 with this token response right so I get the ID of the user the username the email and this is that JWT or token right so this is basically a vehicle with all the information that is needed to identify me so just to show you what it comes up in this token I'm going to jump over to jwt.io which is a cool free tool that you can use to just paste your token right here in its encoded form and then to the right it will decode and show you everything that is in this token so subject that's email address jti that is the JWT identifier you have the email you have the user ID the roles the expiration timestamp the issuer and the audience so you can put in and more things these are just basic things that this token that we're generating is going to have but going forward you can put in more things and put in all the information that you deem necessary for your application or your API to function now let's get started in our code all right so firstly I'm going to bring your attention to and I'm just going to collapse everything that is not absolutely necessary to the to the conversation at hand so that it's less confusing so in our application project you want to add a new folder in the models folder called identity now when adding this folder I realized that I should have put the email and email settings in a folder for themselves but we can do that later on I would put them in a folder called email or mail something like that but for no models identity and then we have these new files so we have auth request which is basically just email and password we just saw that when we were logging in through Swagger we put in the email we put in the password and then we submit it so that's what the auth request is for auth response is what we got back through Swagger the ID the username the email and the token string all right the JWT settings this has to do it's similar to the email settings remember that we modeled email settings of the part of the app settings.json file that gave us all the settings needed for the email well that's what's going to happen with JWT settings so we're going to have a key and issuer an audience and a duration in minutes all being referenced in the app settings file in our API now just like how we have the auth request we're going to have the registration request so office short for authentication I just shortened it but you can be explicit and say authentication but registration request is going to require the first name the last name the email address the username as well as the password so anybody who is registering on the app any new employee who is coming into the company will tell them you can self-register you need to provide this information and then the registration response is really just going to push back with the user ID so after this person has registered there in the system we just send back the user ID that's all that's required now outside of that we also want a new folder in our contracts folder and I'm calling it identity and we want ioth service so we're going to have a new service where we have task auth response login and it takes that request object of auth request and then we have one for registration which is giving us the registration response and it has the registration request and that's really all that is required for the application so you can go ahead and you know review if you need to of course pause as you're going along to make sure that you're getting all of these files and the required fields and notice the validation attributes that are on the registration request because we want to make sure that we're meeting minimum standards our next task will have us adding a brand new project to the I to the infrastructure folder called identity all right so hr.leavemanagement.identity is the name and we would want this one to be at dot net five so I'm going to explain that one yes we're using.net standard for most of the class libraries but in this case we're going to need certain libraries that just cannot work with a.net standard Library so we want dot net five so that we have zero compatibility issues and of course this would carry on into future versions of dotnet so you can go ahead and add that new project I already have it here and in this new project we're going to have a few new folders we're going to have configurations migrations models and services we have new files where we have the identity Services registration we're familiar with that where we're setting up that registration file to be called from the API and we also have our own DB context so I'm going to start off with a DB context because this is probably the easiest one so in the DB context we have public class leave management ID identity DB context inheriting from identitydb Context notice here though that we are typing the identity DB context so I could have done this but I have a special override class for my users so generally speaking identity user doesn't have extra fuse like first name and last name so I have this application user class that I have created in the models folder and it inherits from Identity user so then it has the two Fields first name last name in your situation you may need your users to have more information than just first name last name and email and so on maybe you want date of birth you want other views you can add all of those right here but as long as you're inheriting from Identity user application user can be used to replace identity user in any user related operation thus giving you access to all the fields necessary so jumping back to the DB context we have the same kind of Constructor that you would have seen from our previous DB context where we're taking the DB context options and that will be passed over via the API project in the app settings once again and then we have the on model creating so this time I'm not doing that get assembly I am calling the base on model creating and then I'm calling them one by one in practicality really doesn't even matter so let's just continue so we have the role configuration the user configuration and user role configuration so this is where I'm seeding those bits of data when generating this database so remember I said that generated users before so if we go over to the configurations folder you'll see role configuration where I have row configuration inheriting from Identity type configuration identity role now this one is set up to configure new rules we have the ID the name of the role and normalized Name ID this just needs to be a good so you can go and get a random good um you know generate one online it's fine you can use it there you don't have to use the same one I have but these need to be good so our identity tables don't use integers as their IDs after you're finished with the rolls you would want to take care of the users so users there's a bit more to it but it's really just a bit more because there's more to fill in but it's practically the same concept user configuration inheriting from Identity type configuration relative to application user and then in our configure method we have VAR hasher is equal to new password hasher relevant relative sorry to application user so this is going to be used to Hash the password so we're filling in two application users once again get a good we're giving this one the email and email a normalized email and username and normalize username they're all the same right the only difference is that the normalized versions have all caps if you're familiar with identity user then I won't I don't want to bore you but you can just see I'm filling in all of the fields accordingly and then for the password hash I'm using the hasher to Hash the password um null for the first parameter we don't have to pass in the application user obviously we can't because we're just creating one but we are going to Hash that new password right so I'm just using my special default password that usually meets the minimum requirements to create a user in identity so we have that one for the admin and then we have another one for a regular user so after we have our two users and or two roles I have user row configuration which is pretty much I entity type configuration identity user role and then you pass in that typing for string very important and then we have two new identity user roles we have the role ID to the user ID role ID to the user ID so this is saying role I think this is the employee role to the user that was that's supposed to be the employee and then the role ID to the user ID so because this kind of has to happen in order we need the role we need the user all before the user rule gets generated so I think that's why I just explicitly stated the configurations like this so it would know run this run that then run that now before I go any further I just want to point out some of the libraries that you will need in this project just so that you have you don't have so many red lines so we want to make sure that we have asp.net core authentication JWT Bearer we want core identity identity Entity framework core entity frameworkcore.sql the tools uh the extensions for the config figurations mutantsoft.json and system.identity model tokens JWT so you probably already included some of those because in setting up the DB context and some of the other files you would have been prompted that you need certain libraries so if you have that already that's fine but those are the libraries that you will need overall and as you go along you can just include the missing using statements and references accordingly so let's jump over to the implementation of our auth service so we have the I off service in the contracts folder now we have the implementation we're used to this by now right so we have three fields or well let's start off with the Constructor and how we're injecting the user manager we are injecting the sign in manager and we're looking for i options for the section called JWT settings so you can just go ahead and create those three fields and then in our implementations we have login and we have register and we have a few private methods but we'll just go through them one by one so in our login we're taking the auth request so remember that this is going to get called from the API actually so when somebody hits the login endpoint or when I hit the login endpoint just know the API really just called this method which then made the checks and returned the response all right so we try to get the user if the user does not exist we throw a new exception so we're using exceptions here later on we look at proper exception handling Global exception handling for the API but for now we'll just use the exceptions and we'll refine as we go along so if the user is not phoned we throw an exception could not find that user if the user is found that's fine but then we try to sign them in if they could not be signed in that's just another exception now if they pass all those checks the next thing would be for us to generate their token and that is where this private method comes in generates tokens I'm just going to jump down to that method so you can see exactly what this whole token generation thing is all about so we'll be returning JWT security token which comes in the library for identity model tokens JWT right so you can just as I said include all the using statements once you have your spellings correctly Visual Studio will prompt you that you need reference to X Library so we're generating the token and we're passing in the application user that has been found all right so user was found here and it was able to sign in so we're passing over that user no we get the claims so Claims can be stored in the database claims once again are bits of information about the user you can basically store anything as a claim about the user and a little bit of information that you need for your application to run you can add them to the user's claims that's outside of the scope of this course but I'm just giving an idea of what a claim really is so bits of information about the user and in the database let's get it roles we want all the roles because a user might have multiple roles a user might be an employee and an admin like if I'm a supervisor then I might have to be a supervisor but I'm also an employee so I can approve leave requests maybe but I can also make leave requests because I'm both right so roles can you can have multiple roles for a user get all the rules so then we are now going to just create a new list of claim and then we're going to add to the claims list all of the rules so you see we're just adding new claim called roles to rules actually there is let me get rid of this magic string because there's actually a constant that we can use to make sure that we're getting the correct rule type you know to avoid typos we already discussed why we don't want any any magic strings right so I can add the claim types dot role and claim types is just a constant that has different kinds of claims that are primarily used throughout right so you can always give your own name of our claim but then there are certain standard ones that you can always look for and you can just look through and see which one is relevant but in this case we're adding rows so I'm going to use the claim type for role all right then I'm going to build another array of claims where I'm saying new claim is equal to or new claim is JWT registered claim name so you have claim types versus JWT registered claims so JWT registered claims too much these are JWT specific claims right that are generally used for for applications in general all right so those are like JWT standards versus claim types which is not necessarily JWT related but just user related so you can combine them because they all come down to the same claim type so we have the rows and we're adding JWT registered claim names Sub sub is short for subject all right and that's generally speaking the users the user's username or their email whatever is unique you see jti which is usually just that good string and then the email which is self-explanatory then I'm adding my own claim here where I call it uid or user ID which is the actual ID value from the database so you see you can build your claims you can put in as many claims you can put in your custom names if you want but even even though I have a magic string here I would suggest that if you have multiple custom claims that you need to add don't add the magic strings put them in another constant class similar to how do you see the constants here and then reference them accordingly so you would have your constants like custom clean types dot user ID something like that anyhow after we've built this array we're just going to dot Union the user claims from the database and the role claims and then everything is now in this one array so moving down a bit more what we need to do now is encode our signing key so when we get to the JWT settings you'll see that there is a key that would be unique to your application and there are many ways that people use to store the key in this setting we're just going to use app settings.json some people store it as an environment environment variable I did that in my ultimate API development course so you'll see multiple ways of doing it so all we're really doing here is signing it and what we want to do also is use it to determine the signing credentials all right so between these two lines we have the signing credentials so this bit of code now is where we actually generate our security token so JWT security token is equal to new security token is your that's coming from our JWT settings audience that's also coming from our settings things the claims we just built that ourselves expires we're converting from daytime now we're adding the minutes coming from the JWT settings once again and then we're adding the signing credentials which we just determined here using that signing key and then we return that token so once we return that token see a lot went on in that method after we return that token then we build our auth response which has the user ID the token that we just built I know take note of the code here new JWT security tokenhandler.write token and JWT security token and the email and the username and then we return that response so that was the response that we got from Swagger with the ID the token the email and the username so now that we've done all that heavy lifting between the services and or you know all that code let us jump over to the identity Services registration file where we configure the identity services so like we have done in previous times we're going to need the iservice collection and I configuration and moving down we'll see the different sections so Services dot configure relative to JWT settings we're looking in the configuration to get the section called JWT settings we are adding our DB context and we're familiar with that so you could actually just copy and paste that code just make sure you're referencing the correct DB context file so it's leave management identity DB context which is the one that we just created for this particular project uh and we're adding SQL Server let me bring down the code so you can see it a bit more easily so options.use SQL Server get connection string and this is what I'm calling the connection string leave management identity connection string now the cool thing about it is that you can actually have two entirely different data stores if you need to have a data store for your application separate from a data store for your users then this is it's it's this easy to separate them because all you need is a connection string for one database and another for another we're referencing the other connection string so I'm actually going to be separating those data stores and you'll see that in a few minutes in the app settings so if you wish to use the same database for both then you just need the same connection string no hassle we're also specifying that the migrations assembly is in the same assembly as the DB context which is why we have that migrations folder we also have services that add identity where we're seeing that identity we're adding is application user for the identity user class and identity role and we're adding the framework The Entity framework store to be our DB context that was just initialized up top and we're adding default token providers so this adds token providers used to generate for reset passwords change email all of those things all right so any uh if you have to do that whole confirm email or reset password that kind of stuff this Library will facilitate those token providers for you we are at the services and I'm adding this one as transient because we want a new auth service every time a request comes in so it's not scope this time it's give me a new one every single time and we're just binding our our abstraction to our implementation and then we get to the services.ad Authentication so here we specify options where we have options.default authentication scheme is JWT beer defaults authentication scheme and default challenge scheme is the same thing all right so that's how we tell the authentication scheme to use JWT after that we're adding the JWT Bearer options where I'm saying the token validation parameters are as such in previous courses where I've gone through JWT I was never this strict but you know once again context determines your implementation so for our token validation parameters I am going to need to validate our signing key the issue word audience the lifetime the clock skew which gets or sets the clock when applying a validating time so you know relative to where you are how do we apply the validation time validate the issue sorry the valid issuer is found in the configuration for the JWT settings colon is yours so this is a nice quick way to get a specific value out of our settings um section in an app settings file all right so we're getting the issuer and the audience both from the JWT settings section of the configuration and then our issuer signing key and we saw something like this before where we do the symmetric security key signing for that key that is also found in the JWT settings under the name key then we return the services all right not that bad now that we've done all of that in our identity we can now wire it up with the API so in the API I'm going to start off with our app settings file so once again we have two connection streams I have two connection strings you could have one if you wanted no problem but I have one called HR leave management DB which we're used to I then have one for the identity which I just attended underscore identity to it right so it's really not that big of a deal depending on your business needs you may need to separate them a case for when you would want to separate them would be if we have multiple applications using the same user store so in that situation then you may want a standalone database strictly for user information and then the different databases are relative to the different apps but all apps could subscribe to the one user store and using the same identity library that I just set up and the same connection string setup every application could take advantage of it quite easily you would be agnostic to who is actually interacting with it so we have our connection string and later down in the file I have the JWT settings section so here I just have a key once again this key could be anything it could be a word it could be something like a password but it's not something that you want somebody to guess easily because then people could spoof your token if they know your key right so that is why I said that sometimes people don't store it in the app settings they store it as an environment variable or as an application secret something else but for now I'm just putting it here because it's our application but you know how to store it more securely if needs be our issuer I'm just saying HR leave management and the audience will be HR leave management user and the duration is 60 Minutes meaning this token is valid for exactly an hour after an hour you will need a new token you will need to log in again so it's at your discretion that you set this time some people would set it for days it depends on you and your security policy now let's jump over to the account controllers in the account controller I'm injecting the I auth service and you can see that it's a really simple controller remember thin controllers that's our objective right so there is actually nothing no logic no serious operation happening here we're just implementing two action results one that returns auth response another one that Returns the registration response and then pretty much we're just returning okay awaiting the result of the login request once again in our auth service code we are throwing exception so later on we look at how we gauge those exceptions and have appropriate return messages when our client application is calling but for now this is all we need login and register and then in our startup file which is the second to last bit that we really need to pay attention to we have a few changes accordingly so we want you to configure our identity services and to do this we will need to make reference to the identity projects right so you will be prompted or if if you're not prompted then at least add it as a project dependency when you get the chance and then that will be available to you right so then after we have configured our identity Services another change that I want to point out is to the Swagger so I changed this to a method that is going to configure the Swagger because there are a few things that are going to be different um as you notice my soccer dock was slightly different from the first few times that we used it and this is why so before we get to this method though in the configure for the middlewares you want to add app dot use authentication and you want to double check that you have used authorization so you want to make sure you have those two if nothing else um inside of this configure anything else that you had can remain unchanged now the changes to the ad Swagger dock this is just a private method implemented below so if I just collapse these two you see the add add soccer dock it takes I service collection so in the method call we're passing in the services and in this one now we're expanding what was just the services that had Swagger gen so now we're creating a configuration block where we're seeing add security definition for Bearer so this means now that we're telling Swagger that whenever something is authorized and we'll get to the authorization quote-unquote part of the API but when an endpoint is authorized then require a bearer token that is our security schema for testing that authorize required endpoint I will just give it a little description just some verbiage to tell the user this is what you need to do name authorization in the parameter location is the header so whatever we put in which is the bearer goes in the header of the request and the type is an API key and the scheme is Bearer all right so this is just a slitting Swagger know that if an endpoint is authorized once again require a beer token and that is how it should be handled then we add the security requirements where we say new open no open API security scheme reference API open API reference type is reference type security scheme named Bearer scheme oauth to name Bearer so you see a lot of the things are repeating so you just go ahead and add that section and then we have the same Swagger dock section where we say version one and the type is HR leave management API let me put a little space there all right so that is pretty much it so if I was to authorize an endpoint so you saw me use the API you saw me authenticate but you didn't see me authorize and test so this is all you really need to let the API know that it should lock down everything in this controller if you don't want it on the entire controller you can put it over the specific actions so if getting the leave types didn't require somebody to log in then that's fine however if creating the leave types required somebody to log in then you could put it directly over that post or the put Etc now we're almost done with setting up our identity services and at this point we just need to let the database actually exist and have it updated with the relevant data right so I'm going to in the package manager console and make sure that your startup project is the API and that the default project being referenced here is the identity project all right so the First Command that you need to run is the ad migration for the the new identity DB context so we're going to say add Dash migration whatever your migration name is but then I'm specifying which context without that specification you might get an error saying that there are multiple contexts and it doesn't know which one to use so to get around that you just say Dash context and actual name of the context once you do that you'll get that migration file generated and you will have the tables being created as well as the new data being seeded in for the roles the users and the user role assignments all right now after you've done that you want to do an updates database so the update database is going to look similar in the sense that we have to specify which context we are updating so you just say update database Dash context and put in that identity DB context and with all of that done you would have created the database I can jump over and show you the HR leave management identity DB with all the tables that would have been created once again I separated the application database from the user store all right so let's test this authorization and then we can end this activity once and for all so we're going to say authorize over the get list or get list of leave types endpoint and then we will jump over to Swagger and log in so I'm logging in as one of the seated users I have the token and then when I scroll all the way down so I'm going to test one that is not authorized just yet right so let's look at the get by ID so I can just put in the id1 and execute and you see I'm getting my response no authentication required now if I wanted to test the leaf types I can click that padlock so let me just start it over when I click that padlock it will give me the instructions that we stated so it says make sure that you enter Bearer then space then your tokens this is what it actually looks like going over the wire right the word mirror and that token that I just copied from the response from the login and when I click authorize I can now click close so as far as Swagger is concerned any request that it is going to be sending when we click execute it's going to include that Bearer token in the header so when I click execute at this point then we see our response so let me try it again without the barrel so if I click log out it clears the bearer header and I click execute now I'm getting that 401 I'm not authorized I'm not authenticated right so then let me try it again click the padlock value is the word Bearer The Token authorize close execute and there we go so we have secured our entire API or at least we have put in the capability to have the API secured and going forward of course now we can you know replicate that kind of security policy to our client application all right so we're coming off the heels of doing some heavy modifications to our API in order to facilitate authentication and authorization to some extent now we need to replicate those efforts in our UI where we need to be able to allow user to log in and based on their role they should be able to see certain things or not so here I'm logging in as the admin user and you can see I've made some modifications to the menu where I can see certain items that I could not before so let us look at what was done once again I kind of did the work already and I'll walk you through it because I don't want to bore you with watching me type so step number one let us update our end swag generated code because we modified our API as a result our documentation got modified so we need a fresh set of code to represent the current state of the API so once again we're going to end swag or runtime is.net5 we put in our URL go ahead and create the local copy and pretty much we replicate all of the settings the same name space we make sure that all of the other options are ticked inject it generate the interface uh make sure you wrap the details and generate the details and the class types and when all of that is done make sure that your file output path is correct and then we generate now this is something we might do multiple times and I probably should have shown you this earlier but you can actually go to file and just save this workspace so that you don't have to start from scratch every time all right so I'll just save that and when we come back we can always just reopen it and I just save it inside the project you can save it anywhere that's fine however let us go ahead and continue with our newly generated code which should now have the tasks or the and or the requests and response objects for our login and register operations all right so now that we have all of that let us set up our local I authentication Service so in our contracts we're going to have a new interface eye authentication Service and we're going to have three methods want to authenticate want to register one to log out this could easily be a have been called login doesn't really matter but this is for login this is for registration and this would be for us to log out now of course for every contract there is an implementation so in the services I have that implementation in the form of authentication Service which is going to inherit from the base HTTP Service as well as the contract now there's quite a bit going on in this method and I'm going to walk you through it step by step as usual so firstly I need to inject my I HTTP context accessor and I'm going to have a private field for JWT security token Handler now some of these classes and you would have actually seen this class from when we're dealing with the API you will need additional libraries so as you're prompted to install the libraries go ahead and do that as well as putting in the using statements so in our Constructor as we've seen before I'm injecting the icons local storage and the ihttp context accessor which is getting initialized here we're also passing that over to the base or the client and the storage over to the base we are initializing manually so this the token Handler is not being injected but we're initializing it to be a new instance of JWT security token Handler now for the implementations because of course after this inheritance it would tell you need an implementation so you can go ahead generate those method stubs and let us now look through together what needs to go in each so for the authenticate we're taking email password and I have everything wrapped up in a track catch what we're trying to do is generate an auth request so we'll get the email and the password from the parameters and I don't know if I've shown you this before but in this current in this latest version of c-sharp you can actually initialize a new object by just saying the data type object name is equal to new and then you just have your values all right so that's all I'm doing there then I'm seeing VAR authentication response is equal to away the clients call to login async passing in that authentication request now if the request that token is not equal to string that empty so remember that the request object comprises a few things it has the ID of the user um the I think the email address and other things a few things came back but the only thing really we're really interested in keeping is a token because that's all the application will have to use to say this issue the user is so if the token is not empty then what we want to do is get the token content so I'm saying VAR token content is equal to the Token Handler which was initialized up here dot read JWT token and then we're passing in the string so this is actually a strong type called JWT security token all right then we want the claims from the token remember the bits of information the email the ID everything that was sent back in the token that tells us who this user is we need all of that so I'm just going to parse the claims from the token now this is a method that I have put in and it's done here where it just Returns the list of claims so remember when we're setting up the token remember we compile the list of claims and compressed it and put it encoded it and put it in the token now we're decoding it so that we know the list of claims so in this method we're basically saying VAR claims is equal to tokencontent dot claims dot to list so this whole token content object allows us to just get the claims back as a list of string all right our list of claims rather and then we're going to add explicitly the claim types name is token.subject so maybe there was any maybe there wasn't I'm doing it explicitly I'm just showing you because maybe you don't know what you're getting back in the token sometimes so you if you want to be explicit you can always add your own claim with your own name just like we saw before and you put in whatever value it should have after doing all of that we return that list of claims all right so now we have the claims I need to create a user for my current APP so I'm saying VAR user is equal to claims principle and claims principle will have a new claims identity with the claims that were just you know taken from the token and we're using cookie authentication so once that person is created we're storing that user record or that user's session the fact that they're now a user currently in the system as a cookie so we'll see how that is set up later on in the startup but that is what we're doing and then we're going to do a login by saying HTTP context accessor so this is a really cool library in case you're not very familiar with it that allows you to actually access the context of the HTTP requests so everything is happening when a user is requesting data or sending data whatever it is they're doing it's all happening within the context of an HTTP request so this Library actually gives us access direct access to that current request Pipeline and allows us to manipulate HTTP context and it's injectable so we don't have to do it from the controls we can do it from anywhere else so I can say give me the HTTP context that we're in and go ahead and sign this user in using the cookie authentication scheme then we're going to store that token in local storage for safe keeping so remember that we have the local storage being called by our adbeer token method whenever we are going to do a client call so that is why we have to store it once we get it and then we're just going to return true so if the person was authenticated we do all of that and return true if we return false then we can do something else and you see that in a few minutes so that is pretty much what authenticator is doing and if there was an error in this try catch then it just returns false there's an error right so that's authenticate let's look at register which is much simpler really we're just going to formulate that registration request based on all of the parameters that would have been passed in and you know this could really easily have been an object but that's fine you can refactor that later on but we create that registration request accordingly and then we pass over that register async um HTTP call with that request and then if we get Market user ID registration or successful otherwise it was not now in our logos we're doing two things really we're just clearing the storage of any token values that were there and we are also signing out and implicitly destroying any user-based cookies that were created during the signing easy that's pretty much all the logout is doing all right so that's it for our authentication Service not too complicated right next we need the user interface or interfaces that we'll call this so I created to a controller called users controller and here we inject I authentication Service and have two actions one for login and one for login with our post all right so login it's just going to return a view and we can generate a view quite easily with this so well let me backtrack I'm actually using login VM so I created a login VM there we go which enforces some validations remember I was saying that we can always enforce validation from the client side and don't have to necessarily rely on the API so something like logging in you shouldn't be able to attempt to log in without the email and password being filled in I also have a field called return URL all right so whenever you try to log in we're going to require that you have email password and we're just also validating the data types with those and then in the in the action we're going to generate a view and I just said raise a view login I use the create template because we are going to be we need a form and then we're using the login VM for that Generation all right so after doing all of that and we click add then we get our simply enough view that we're used to seeing in our users folder and it's really just a login form right um I put the you return URL as a hidden and we have a text box for our email one for password which I specified the type is password so that it has the characters of course and then the button says login now when that form is submitted we're taking the login VM and the return URL so return URL is going to either have content or default URL content root and we are going to have a flag that says is logged in which is going to be set after awaiting a call to the auth service.authenticate and we're passing the login.email and log in that password and if we get a Boolean then we can return redirect to that return URL all right otherwise we're going to be adding a model State error to say login attempt field please try again and then we will just return The View with the login so remember that once it calls this and this one block comes back as true that means you would have already created the cookie already created that user record or that user session and then by the time we're redirecting that user would have been logged in now let's jump over to our layout and see some of the changes that we meat so in our layout we had our Leaf types link or URL right here in this menu section so I've removed that and I've replaced it with this nice little block of code and I've also put in this partial called login Powershell but let's look at the little bit of code that I've put in so in this UL or unordered list where we have all of our nav items I have put in an if statement that says if user so user with a capital u defaults to look at the claims principles remember that's what we just created in that authentication Service right so if this user dot identity is authenticated then we want to do this so I'm checking user dot is in role so remember that we sent over the role claim right so we can just say user dot is enroll look for the role administrator and if the user is in that role then we display these mini items so I just have another nav item with a class called drop down and an anchor tag that says manage and I'm not going to go through every single character I'm just going to scroll across slowly enough so you can see all of what goes into that anchor tag all right and then below that we have a div that has the drop down menu items so you can just hit pause and replicate that if needs B all right so that's how we got that drop down list item in the menu at least if you're using bootstrap 4 which comes default when you scaffolder.net file application now in the login partial I all I did was create a new razor view didn't use any model or anything just an empty Reserve you gave it an name underscore partial Donna Square usually indicates that it's a partial anyway and then we have this bit of code where I have another UL with class navbar and then inside of that I have an if statement if the user is authenticated then we want a list item that shows the user.identity.name so remember that name claim that we set explicitly that's what that was all right so that's where you get that username to be displayed in the nav bar so at that uh display right there and then we have a logo button so the logo button is actually a form that is going to call the action logout in the user's controller and I just included that return URL right there and then that button just says log out so if the user is authenticated it shows that else we want to show a link for register and a link for a login all right straightforward enough so if they're not logged in we want them to be able to log in or register otherwise show them their name so you can go ahead and replicate those lines other big modification that needed to be made was to our startup so you can see here that quite a few things have happened the last time we were here I believe we would have had up to this point now we have all of this preceding it right so firstly we have to let it know that we want to add the HTTP context accessor meaning we want to allow it to be injectable into any other class so we use it in the ioth service this allows us to that facility all right then I want to set up the cookie policy options right so so services that configure cookie policy options and then we're passing the minimum site responsible uh sorry minimum side same side policy is same side more dot none all right so once again this is a pretty simple app I'm not going all out with the security you may have different security needs around your cookies and your policies but at the basic level this is what we're setting up then I'm going to say Services dot add authentication and we're adding the cookie authentication defaults authentication scheme and we just add cookie then I'm adding transient or adding a transient um registration for our I authentication Service with its implementation everything else remains pretty much the same in that Services configure Services method but then in our configure we also want to make sure that we add authentication and that we have ADD or use authorization there also so you want to make sure that those two lines are present and before I move forward we also want to make sure that cookie policy is there so three things actually cookie policy use authentication and use authorization now one other thing that you want to do is modify your services so now that we know that we have to have the bearer token attached to certain service calls we can now go to a service so we have the leaf type service already up and running and then we can call the add bear token method inside of each of these methods so right before we actually meet that client call we want to add their token and just as a refresher add bear token basically says if the token exists then go ahead and add it to the authorization all right get it add it as a bearer so remember when we're testing it with swagger when we had to test the secured endpoint we have to go and say Bearer space the token that's all this is doing it's just seeing the authentication header value is bigger and we're adding that token and authorization is the default header right so that's the header and it's adding Bearer this is basically putting that Bearer space token for us when we do that we're adding it to that client so by the time the client makes the call the bearer token is present and then everything else can flow so you can just go ahead and add that beer token because we don't know when something will be secured or not all right we don't know which endpoint will be secured on the API um well it doesn't really matter the fact is that we know we need Bearer security um and more than likely you would lock down your API or an API would be locked down completely to anybody who is not logging in or trying to register once you're logged in you're expected to have your token to say here I am please for the information now as a test what we're going to do is jump back over to our Leaf types controller in the API and put a an authorize over the entire controller which means that you should not be able to get to any of these endpoints without your Bureau token you should get a 401 which means unauthorized or well on office on authenticated rather if you attempt to go to any of these endpoints from the API all right so remember to test you want to make sure you have on multiple projects multiple startup projects go to solution properties and let the API start I'm starting without debugging so it comes up faster and the MVC can also start without debugging if you don't need to you know go line by line so let's go ahead and test this all right so we have up our MVC application we're going to try to log in so let me put in a bad attempt I know that user doesn't exist log in and give it a few and then it's bouncing boxing login attempt failed please try again all right duly noted let us try one that we know and then try that again and then this time we are now logged in so it redirected us to our home page and now we see that manage menu item which gives us those options because we're in as the admin now if I go to Leaf types everything loads why because my token is present it knows that I have access the information being requested now if I log out and let me try and log in again as the regular user then login is going to be okay but there is no manage right now what if this user was standing over the admin shoulder and saw that in order to get to the leaf types and create my own leaf type I can do this I'm going to try and get there it's going to go there right so Auto Rectify this we have a few points of attack and once again where options implement the one that is best for your situation but from the client-side application we should know that certain things are reserved for administrators and certain things are reserved for users or maybe not reserved but users shouldn't be able to access certain things administrators can so in our Leaf types controller it's probably not enough to just say authorized because this means you have to be logged in I could also say authorize with the roles administrator so that means only administrators should be able to get into this actual part of the application all right so that would actually save me a lot of time on the client side trying to figure out okay what are they calling or who are they whatever because this authorized will actually take care of that entire situation for me all right so now that I have authorized only administrators to be able to access the leaf types controller if I am logged in as a user and I attempt to go to leave types manually so once again it's not enough to just hide the link because if I memorize it I can try and go well you're seeing that it's saying access denied and it's pointing to an address that doesn't exist but that's fine but it is telling us access denied um or you know it's reporting that we can't get there however if I was logged in as the admin I could easily navigate there because I meet the requirements so that is a nice way to secure your application from the client side now that being said you could also secure it from the API set because the same way that you can set that authorized flag over the leaf types controller in The Client app or whatever type of app you're using whether it's an MVC Blazer or angular however you set the authentication in those you could or authorization rather you could also set that authorization on the API so the API developer may also have strict stipulations as to who should be able to access my controller because if it's not enforced from the upside then we could still get over to the API so as API developer you could also be very strict and say that only administrators are authorized to hit this entire endpoint this entire Behavior right or Suite of behaviors so as I said there are a few options and you can always attack it from different angles all right so let's close out this entire activity with a few more modifications and then we're home free at least for now right so in our users controller in our app I want to make a modification here where I check if the model state is valid so if you use the MVC you know what this does you cannot proceed as long as their validation errors and the fact that in login VM we do have some validations we want to make sure that those are in check and in place this is how we enforce that validation before we even try that API call all right otherwise it will just add that new that static error and return The View with the data and the errors no problem now for register let's go ahead and scaffold this one so we just go to view add new view uh raise a view we want register with a create template and our our class would be register VM all right so I'm not sure if I showed you the register register VM but it pretty much looks just like the registration request registration request first name last name email username and password all right and if you want you could put in a confirm password but for now that's all we have and we also have those attributes to make sure that they are required so you're going to use that to generate the view and then in the in the post what we're going to have is US accepting that registration or register VM now I have made a modification to the register method and this has a few steps to it one in the mapping profile I've added a profile for the register VM and registration request remember registration request is one of those generated models courtesy of nswag right so I'm mapping this to that because I I wrote it but I really didn't like it and once again when you're developing sometimes you do something one way and then later on you're saying I could have done this a little bit better no problem with refactoring right so in the register method I am now taking a register VM parameter and I've also updated our I authentication Service to reflect that all right so now it takes that whole object instead of six parameters so that's another thing with solid principles you don't want to be passing too many parameters into a method so when you realize that you probably exceed three or four create an object so in this case we only had two I didn't bother to refactor that one but then this one had about five or six so I refactored it to just pass in that registration object and then our registration request is now just a mapping between the registration request and our registration or register VM right so of course I have to inject Auto mapper into this to get that up and running and then everything else Remains the Same pretty much so back to the controller I know pass in that register call I check is it created and then if it is created then we redirect so here I'm just setting the URL to be URL content I'm just hitting it specifically and we redirect otherwise we have a message and return The View with the data and it would show all the validation errors accordingly so let us also modify our auth service at the API level because we want employees to register so we need to know that they're employees so at the point they're registering based on our code is set up now they will just be users there will be no role assignment whatsoever so we need to ensure that when they register we know their employees so in our auth service once again in our identity project on the infrastructure right auth service we need to say if the result was successful for the create user then we need to assign them to the role so we're just going to add this line after result that succeeded we just say a way to user manager add to roll async user and employee so let us state that registration for a spin so I'm going to hit register and fill this out now one thing I want to point out we do ask for the email and the username once again contexts are different in our context I am using the same value for email and username and then it would be said it could be said the Bible that asks for both why not just ask for one and assign it in the back end which is a verifiable argument right so in your situation you may need them separate and they may need to be two different things that's no problem just giving you the framework so before I even do a proper registration you can see that the validation is actually actively working I cannot proceed until everything is in place right so let me put back the values and then go ahead and hit register and I was redirected here so you have another you know I'm always talking about the options because at this point I'm registered but I don't know there's no indication to say it was successful I just went back to the home page of course if I attempt to log in I am able to log in but the user doesn't know so generally speaking or sometimes what you would see is that they would actually log you in after a successful registration so we can make a simple modification for that to happen that's simple modification is to call or authenticate all right so we went to the registration we got the response if it is not empty and we would have returned true before we return true we just want to call authenticate which we know what it does it actually triggers that whole login procedure and then we return true so then in our controller we could easily just have some redirection to say instead of going back to the home page we could actually redirect to a page that says you have successfully logged in or some friendly message to the user so they know exactly what has happened all right so that's really it for now at least later on we have the beautification we have some modifications because even up until now we are not um focusing or compensating for certain errors that would be coming back from the API so one we still have Global error handling to take care of but later on we will deal with that right now we're just focusing on implementing these features and making everything work well together all right guys so now that we have our authentication set up we have our users or at least our users have the capability to self-register and be set up as employees now we need to put in the feature that allows the administrators to allocate the days to send employees so that starts off with us modifying our domain objects for leave allocation where we're going to add the employee ID because we need to know to whom the number of days for this leaf type and for that period have been assigned so we need to add that and then following that we do a migration remembering that we need to set our startup project to the API and the default project to the persistence project and or add Dash migration statement will look like this I named mine added employee ID to leave allocation and the context Will Believe Management EB context and then after that we run that update to the same context so this is our migration file you just do the update database and once all of that is completed then we can move forward the next thing that we want to do is to create a contract file or an interface in our application layer under the identity folder I'm calling it I use a service so we're going to have any specialized user operations in this iuser service that can be used by our handlers so I'm going to have this one returning a list of type employee and it's called get employees because we only want to allocate this to the employees now the HR department said that all they really need for this feature is the ability to go to the page and click allocate and then we get all the employees and allocate the default days for the period period being this year of course we don't want to allocate anything to anybody who is not in the employee role so we need to make sure that we're getting employees employee is a model that was created inside of the identity folder and all it really has is the ID the email the first name the last name nothing too much not too much coming from the database just enough for us to know who this employee might be next we have our implementation which lives in the identity project and it's just user service under the services folder and it's inheriting from the contract and it's injecting the user manager relative to application user and then our method for getting the list of employees we're just looking in the user manager get users in role async and we pass in that role so this is guaranteeing us that we're getting anybody in the database with a user who has an employee role and then we're returning uh the list of type employees so we're just this is a list of application user so we're saying dot select from this list into new objects of type employee and they were just reassigning the values accordingly and then we end it with a two list all in that return so once this service is called we're going to be using that method to get all of the employees then in our identity Services registration method of course we have to edit iuser service so we just go ahead and register it accordingly now this is going to be followed by some changes to our I leave allocation repository so jump back up to contracts and find our original I leave allocation repository now I originally would have written the implementation for the full crude capabilities of I leave allocation alongside these two custom methods but then HR once again kind of changed rules made it simpler for us so no problem but we do need some more custom methods in order to accomplish what HR had in mind so right now I have a task returning Boolean that checks if an allocation exists so we get the user ID the leaf type ID and the period and then we have another task where I'm seeing add allocations so you're going to see why I have ad allocations even though we already have the generic ad method please take note of the fact that this one takes a list of leave allocation as the parameter now in the implementation let us see what is happening here so let's start off with the allocation exists once again task returning a Boolean checking if it exists I will get these three parameters so we're just returning dbcontext.liveallocations that any async where we check if the employee ID matches the user ID being passed in if the leave type ID matches one being passed in and the period matches the period so we're just returning yes that allocation exists or no for our ad allocations we're doing something a bit differently here than with the Regular Ad because what happens is that if we are if we're allowing HR to just go and click add allocations and there are 100 persons there what we don't want to do is call the add function 100 times so if core actually gave us an ad range method that allows us to just put in a whole list of Records to be added and then it will package it in the most efficient SQL statement possible to save the changes all right so that's why I wrote that customized method here so we're adding range instead of adding all right so now that we have our uh our repository is up to scratch let's jump over to our Handler and see what changes are needed over there all right so in our Handler I had commented out these lines so I'll just uncomment them now that we're here so we're injecting our user service into our Command for create leave allocation now a few other changes will be needed because our create detail is asking for too much information based on what we said the new operation or the new objective is you'll get to that in a few but right now we want to focus on what Handler does after it is it has validated the data that came right so after validating what is in the dto we then proceed to try and compile the list of allocations to be sent to the database so let's see what happens here firstly we get the leaf type that is being allocated right so we do a get request on the leave type repository which was already injected courtesy of the fact that we needed it for the validator all right so leave type repository dot get request dot leave allocationdto.leaf type ID we get all the employees courtesy of our user service we set the period to this year and then we initialize a list of leave allocations then for each employee that is in the system we check if the allocation exists already we just continue otherwise we want to add a new allocation record where the employee ID is equal to EMP dot ID the leave type ID is equal to the leaf type dot ID in the number of days and the period is the period right now I'm not being strict on business rules some business rules would say that based on the point in the year that allocation should be different which is perfectly plausible whatever Mass you have to do you apply that mass against the default days and you apply it but the point is that you're allocating the days to the employee at this point of course if you wanted to get that granulo then you would want to do it on a one-to-one basis as opposed to a bulk operation for everybody for an entire period of a year right so you know you can play around a bit with it but right now we're just dealing with the bulk operation so after we have added all of those allocation records to this list then we just await our call to the ad allocations in our repository which is just sending over the list and EF core will do the rest and then we can say response is true success is true rather and the message is creation or allocations successful whichever one you prefer now for our create allocation dto we're asking for the number of these and we were asking for the period because at least in the old system we were able to click directly on an employee and put in the number of days that we're allocating manually and the period that we're allocating it for as HR said they kind of don't need or don't want that right no so that's fine we can always just modify our detail scale it back a bit and of course that would have some Ripple effects with the whole you know um the inheritance of the eye allocation details so that means we have to modify more than just the fields right so I would have to remove this inheritance and then I would have to modify also the validator to not include all the rules relative to the the interface all right so I'd have to remove this whole include and then I'd have to rewrite the rule just for the create so I just rewrote that rule where we validate the leave type ID that is being applied for or allocated for we make sure it's greater than zero and we check if it exists also now let's jump over to our API and let it know that it should also be returning the base command response so if you haven't done that one already make sure you do that so that the Swagger document will be up to date and then two changes need to be accounted for by our new service client in the application because one we change the parameters for the dto now we only need one parameter and we also need to let the service Knight know that it should expect the base command response so now that we've made those changes let's use n swag to regenerate these the service client code just always remember that it's best to run the project and then even if you have it saved already because I just you know opened my saved version of this template even if you have it saved it's best to reopen the project recreate the local copy and then you can regenerate your c-sharp code so now we jump over to our client application where we will be setting up our contract its implementations and of course the user interface so right now we have our contract I leave allocation service and it has a task there is returns response with type int and it's going to be called create leave allocations and it's only taking a leave type ID once again HR simplified it for us so if you had created all VMS and so on that I have that would have been Overkill based on the new requirements but that's fine so all we really need is create leave allocations and then in the implementation which we put in the services folder of course we know that we inherit from the base HTTP service and the I leave allocation service much like what we did for the leaf types we also inject our local storage and I client into this service and then in our method that is creating the leave allocations or we have a response type which is response relative to type int we create our detail which in this situation is really just the detail to say leave type has that value all right so we know the create leave create leave allocation detail is now updated to only want that value since we updated our documentation and the resulting code through and swag we add our Bearer token and we await that call right so I'm adding the Vera token we can always double back and make sure that the API endpoint is protected um for administrators only and we can also do that protection from our application side right so the bearer token is definitely important remember it's always going to be important for API Communications uh so after we do that we check if it was success then we set it to True since there is no real data coming back because we're only returning the base response we're not returning like an ID or something so I don't need to set response dot data to have any value really um and then we compile our errors return the response and we're also catching any errors like I said before make sure that you have it registered in the startup.cs so you just jump over to the startup.cs and if you had written the lines and commented them then on comment if not then feel free to now put this line now let's make changes to our user interface so the best place that I have surmised to put this feature for a bulk allocation of leaf types is on the leaf type list right so on that page I have just added a new form where we will have allocates with the same kind of root ID basically it's the same looking formula to delete so here we're repeating the form so as I mentioned sometimes peep instead of having multiple forms would have one and then use JavaScript to trigger the one form but that's okay in this situation all I want to know is that it works right so we have the ASP action allocated takes the same root ID and we have a button that says allocate and this one is just saying are you sure you want to allocate to all employees that is the prompt that you would get now we have a post method in our leave types controller called allocate so I just put that one right underneath the delete right so in allocate we are are trying to get the response from leave allocation service so that's the point though that we have to inject that into our controller all right so we try to get the response I just use Ctrl M and O just now to kind of collapse all the codes so you can use that for big code files so our allocate method is going to call allocation service create allocations passing in that ID and then if it was successfully redirect to action to the index and well I'm just going to return bad request here just in case it was not successful so we know it was an error later on you can add some jQuery or something to handle the return type in a better way but right now we're not prioritizing that we just want to make sure that we're putting all the the things and the foundation in place right so let us actually take that one for a spin let us try and allocate remember to put on multiple startup projects and having logged in as the admin user we navigate to our leave types and then we try to allocate so we get our prompt are you sure we click OK and we're getting an error we are getting an error HTTP error 400 so this is indicating that bad request all right so something definitely went wrong so after tracing and tracking down that error it landed right here in the validator so what happens is that when we're creating it is not coming across as valid that create leave allocation D2 is not being valid that is because it is seeing that the leaf type does not exist now we know that's impossible because we just clicked on the leave type it's in the same line we know that it exists and the error is right here so that that is my bad so a unit test probably would have caught that we haven't written any unit test so we have to spend time tracking these things down but the point is that we should be returning if it exists because we're seeing if it exists or true so it must exist so this must be true so I shouldn't be returning returning not true or not all right so that's that's an error on my part so because of that error actually we'll have to go to Every validator just to be you know wholesome to make sure that none of those validators are making that same mistake now the good thing is that we kind of created Central ones so we don't have many many changes to make so just take off that not sign off the leave type exists check and we should be good to go all right so let us try that one again let us try to do the allocations all right so we're back and then let us try the allocate again we get our prompt it does its thing and the page refreshes so there are no indicators right we could of course code in some messages to say you know this action will call was completed successfully but the fact that it re-re refresh the page according to our code if it is successful then redirect to the index of the current page which is good it wasn't successful so it went to bad request so at least we know that our allocation is working let us check in the database to see what allocations have been created and we see here that we have allocations for leaf type 1 for the period of 2021 and the employee to whom it is assigned so we have three employees in the system or I have three employees in my system we're probably just seeing one or two if you have the seeded user and you created a user since but the point is that we have as many employees are in the system you'd have those allocations so if I do that again with sick leave which is id2 Click allocate click OK it does its thing if I refresh this data now we're going to see allocations for sick leave for all the employees so leave allocation is not working that's what HR asked for that's what they get so later on you see they have the foundation now to extend this if you wanted to give a dedicated screen you'd have to go fetch the employee allow them to edit the allocation manually and then you know how to set up your Handler and your API endpoint to be specific to that we're not going to get that detailed right now we just want to get the base functions done and so far we're finished with leave allocation all right guys so we're winding down nicely and we're moving on to the next module which would be our leave request module so our journey here starts with a modification to our leave request domain object where we're adding requesting employee ID all right because whoever is logged in is the one who is going to be making the request so we need to be able to say that this request came from this user as usual following a modifications or domain object we have our migration command and then we have our update database command so you can go ahead and do those two and once you have successfully completed that we can move on to our next activity let us review our create leave request details so we said that or create leave the request detail needs to have the date we would start and end dates the leave type being applied for as well as request comments notice there is nothing here about the user ID right so you're probably wondering okay so how do we know which user is logged in at the time so remember that we are using Tolkien authentication which means that between the MVC app and the API we can access different bits of information from the token one bit of information in the token would be that user's ID however I don't want to access it from either of these places because I don't need to access it until I'm really creating believe request and we have the Handler here that is taking that command request or that command object and then it is going ahead and validating it and then creating that leave request if it is valid and then passing it to the database so that means in between these two steps we need to make sure that we put in that new employee ID data so remember that we had used the context accessor back when we were doing the authentication in the MVC application the cool thing about it is that we are able to use that context accessor all the way over here in our application layer in our commands so we're going to access the HTTP context of the API from inside the Handler that way we don't have to access it until it's absolutely necessary so in the API startup file I'm going to add the services dot add HTTP context accessor right above the swap add swaggerdoc method call this then enables me to inject into the command my ihttp context accessor and I can go ahead and initialize the field but I do need a library for this and that is the microsoft.sp.net core HTTP abstraction so go ahead and install the latest version using nuget rename our field according to our naming convention and then inside of the Handler I can easily save VAR user ID is equal to my HTTP context accessor.http context dot user dot claims first or defaults it's a quite a mouthful but let's just assess what's going on here up until this point we have gotten the claims principle that claims principle is the same claims principle that we're able to build in the client application by virtue of the token right so because the token is coming over from our client to the API where able to access the token information from the Handler courtesy of the key API and then we can access that user look inside of the list of claims and find the first or default that has the same name type key however you want to assess that but the type here corresponds with the claim name that we would have given it for user ID so that's another reason I would suggest not using the magic strings because one spelling error here could throw out the entire thing but we can do that in the cleanup activity later on but right now we're getting that claim uid which we set manually and then I'm just using the default or for if it's null we don't get another exception but I'm really getting the value alright so that's how I get the user ID now that I have this user ID later on I can say leave request dot requesting employee ID is user ID now I did it all the way up here because I may want to use this user ID in another operation later on so I'm I'm just keeping it here and another thing that we might be interested in is the email address so down here we are getting the email in a slightly different way where we're seeing email address is equal to http context accessor all of that user dot find first and then we're looking for the exact email Claim by its type so you see that's a different technique to what we did up here and we're getting that value so you can take multiple approaches to get these bits of these bits of information because you could have just gotten the claims principle in One Sweep and then use the find first or the first or default afterwards to get whichever bit of information you want no problem but at least you know now how to get the email address so we can now say to that email address and dispatch our email at the appropriate time now before we move on from this particular Handler there are other housekeeping operations I would want to carry out before we allow a user to proceed with a leave request so let's think about what exactly needs to happen during this process one a user needs to state that they want to have a certain leaf type during a certain period they can add additional comments if they wish and then they submit that they can only get that request if they have the allocation so that means we're not even going to put it in the system if what they have requested exceeds their current allocation if they request it and it their allocation is present then that's fine later on when an admin approves this then we go ahead and do some deductions to make sure that when they if they requested five days then there are five days the less in their allocation so those are little things that we want to be keen on now this is uh this is the most complicated of the modules so there's quite a bit of work to do here so let us start with a checking for the allocation because if they don't have the allocation then they can't have a valid operation going forward right so let's go ahead and inject our I leave allocation repository into the system and then what we want to do is be able to look up the allocation for this particular employee which is a method that we do not have all right so let us jump over to that repository and Implement that so we're creating a task that returns leave allocation I'm calling it get user allocations and it's taking that string user ID as well as leave ID right so we're going to jump over here and go ahead and implement the interface in the implementation repository class and then what we're going to do here is do a lookup and return our DB context looking in leave allocations finding the first or defaults where the employee ID matches the user ID and the leave type ID matches the leave type now back in the Handler I can go ahead and get that allocation by calling leave allocation repository get user allocations passing the user ID and that request dot leave request detail.leaf type ID I'm now going to calculate the number of days requested so I'm just doing a quick calculation between the end date and the start date to get the total number of days and I'm making sure that I get it back as an integer and then I'm going to say if the number of days requested is greater than the number of days in your allocation record I'm going to add this validation error so this operation could have happened here right as we're seeing I'm doing it in the Handler and I'm using the fluent validation result to just add that because in case it's not valid I want to make sure that this validation is also present and so when it's returned with the errors that will also be there now I'm doing this in the Handler but I could have easily done this in the validator also but then of course I would have had to inject all of this and create a custom validation on the end date to make sure that I do that calculation and everything so I'm just giving you the options you know based on your situation you may want to keep all of those things inside of the validators you may not even be using validator so you could be doing all of this validation right here it depends on how you want to play your application code out so now we can just go ahead and clean up anything else in this Handler we may have to revisit it but at least we're looking at how we expand our Handler and start putting some other things in there like the HTTP context Handler right um access or rather sorry so when we move on you can clean up any little messages along the way and make sure that your code can compile so I'll just do a quick build now let's fast forward to our app we want to get the feature inward at employee can request leave first and foremost before putting any other administrative features and anything right so I want us to make sure that we have that view model I would have showcased it before but leave request VM and I put up I have all the view models here and these view models are really coming from the existing code largely so I have the create leave request VM and that takes the start date the end date both date time the leave ID and some area for comments now I would jump over to the contract for the I leave request service where we have a few methods we're not implementing all of them just yet we're dealing with the create so you can go ahead and put them all in and create the matching service implementation and allow it to implement them all but in focusing on the create method what we have is similar looking code to what we did with the leaf types however you would notice that I have a red line underneath the part where I'm asking for a response that's because as far as I service client or or into our code is concerned we're still only looking for a task that is because in the API I need to do two things I need to let the documentation know that on post it should take the base command response remember that we had outfitted all our handlers to return this and this is essential because when we use n swag to regenerate our code which I'm about to do then it will know that it should expect this response type once again create the most recent local copy go ahead and generate and know that that is done when I jump back over to my code there are no red lines because now it knows that it is returning the base command response so everything is good all right so that is basically what we're doing in creating the leave request so let us now focus on setting up the controller and the supporting code I went ahead and created a controller with read write operations we know to do that now and I injected the leaf type service and the leave request service so you're probably wondering okay why do I need the leaf type and leave request service if I'm only creating leave requests well the thing is that the view which I have already created needs to have a drop down list for the leave types because when somebody comes to request leave and it's based on your flow but the way we're building it they come to request leave they have to select from a drop down list which leave type they're selecting for the start date the end date and then they are able to put in their comments all before they go ahead and select request all right so that is basically what I'm doing and this is the view coming from the old system so literally I've copied and pasted this view from the old system the only update was that we changed the model to be the new model as opposed to whatever name space was there but I'm just showing you that it's the same class so you can always go and get the code file and just copy and paste and you should be up to scratch as I want to offer that's why this is here I'm not using any date Pickers I'm not complicating the interface just yet so I'm removing that date picker reference and we're just using input type date so we're depending on the default date picker given to us by the browser so back in the controller we need to prepare that drop down list before the interface loads so instead of our get create method what I have is a call to the leave type service to get all the leaf types store them in this variable and then I have leave type items where I'm creating a new select list with leaf types and using ID and name as the key and the text fields and then I'm creating the new model where I'm passing in leaf types as leaf type items remember in create leave request we had that public eye numerable select list item property and this could easily have been select list all right so whichever one works but let's just work with select list because it's actually easier to type and work with so that is all that's happening here and then we return the view showing the model now in the post method we pretty much follow the same procedure if the model state is valid because remember that in our view model we have a few validation rules so we want to make sure everything is met before we can proceed as a matter of fact I'm just realizing that I'm missing a validation rule over the leaf type ID itself so they must select a leave type ID before they can proceed all right so let me just space them all so we can see everything there we go so if the model state is valid then go ahead and wait on the response from the leave request service word which is going to attempt to create the leave request and then if it is successful then we can redirect the index there is no index page here just yet but that's no problem and then we can add any model uh model State errors coming from our response validation error but then if the page has to reload what we need to do is actually reload the select list of leave types right so one thing with drop down lists in case you're not so familiar with them anytime you're loading the page you have to load up that list so we loaded the page first here we have to load up that list then return the model we have to do the same thing here but then we already have the data coming in from the model so we just need to reassign the data to the newly loaded select list before we return the page alongside any errors that need to be displayed now I've added authorize on this page that's pretty standard at this point and in our layout file we have a few changes so I have put the links there only for employees to be able to go and create or view my leave I haven't done my leave just yet but here are our links right so in the same part that is checking if the user is authenticated I'm saying if it is an employee who is logged in because administrators don't have allocation so they don't need to go and request leave right so if it is an employee who is logged in then they can see two new nav links one go into the requests and create and it says request leave another one going to my leave which we haven't done as yet but we're getting there slowly but surely right so after doing all of that let's just go ahead and set our multiple startup projects once again and test this out so now I'm going to log in as the user not the admin but the employee and once I do that I see my two links in the nav bar so when I go to request leave I am getting this error it is a 403 error and I see it and I know exactly why so I have mentioned that we are yet to compensate for all the exceptions that might be thrown via the API this is one of them this is a 403 which is an unauthorized exception the problem is that back when we were testing how to lock down our endpoints we had set authorized administrator on the entire Leaf types controller so now this employee needs to have the list of leave types displayed to him it the application is making that request on this endpoint but he is not an administrator so what we can do here is take the authorize off or at least the rows stipulation off of the authorize and only authorize those that are augmenting the data so like the post the put and the delete now with those adjustments maybe we can try this operation again and voila so now we can safely navigate there as an employee so let us try to apply for vacation leave so I believe that this state as you can see that it's going all the way back to January I guess the start of time we can always set defaults because you probably don't want that expanse of time but we're not going to do that for now what I will do is simply select the 1st of January to the 5th of January and notice it's months day year that is the format it's using all of that is customizable um but you won't get all into all of that right now so vacation leave and then when I request leave I am getting another error so this error is seeing that parameter cannot be null so I suspect that this is an error coming back from our API that is not being handled once again but let us go into debugging mode and see exactly what the problem is and here is the culprit the culprit is on us trying to get the email address so let me just backtrack a bit we do have the user we have the claims and if you look in there we do have the email address claim all right so the email address is present however I believe I'm using the wrong claim value here so if I go back to where I generated the JWT which is in the auth service I did use the same claim name which was simply email right so if I right click or control click you'll see that it's just a static text email however in contrast it is actually seeing that claim with a different key and that key is more fitting off the XML soap schema and that claim type would actually or that text would actually be present in claim types so let me stop and go ahead and change that to clean types dot email so it failed on the email address retrieval and that is why we didn't we got that error right so if we check or leave requests table I'm pretty sure that we're going to actually see some data right so you see here we do have vacation leave and it's there for every time that it was pressed right so it is indeed working it was just failing on the retrieval of the email address so with that fix we should be able to proceed on on hampered but then you do see that something completely unrelated to the key operation cause the failure which is kind of why we tried this whole try catch to just send the email without bothering everything else but then we see that this is also a failure Point granted we just fixed it but we could theoretically take this and also place it inside of the track catch so that anything email related doesn't throw an error now that we have the request process done let us take a break and when we come back we'll look at the approval process now that we have our leave request on the employee side down we need to actually put in some other things so that the administrator can actually see the pending the requests and approve or reject now this comes with some breaking changes to solve the handlers and some of the requests some of the details quite a few things that we have done up to this point but as usual I will just walk you through all the modifications needed so I'm going to start off with the fact that I actually went ahead and created a cost Constance class for the claim types remember I discussed removing the magic strings like putting in uid manually right so I created that custom claims types um it's just a public static class it's in constants under the application project and we have public constrain uid equals uid so this now allows us in the auth service to say customclaimtypes.uid and pass that in and anywhere else that we you need to reference this custom claim type like we did in the other handlers then we can just go ahead and say custom claim types Dot uid now another modification that I'm making is to our user service I had one method getting all employees now I have another one to get only an employee based on the user ID all right so in the implementation of that method basically I'm just saying get me the employee find by ID and then I'm returning a new employee object with the various Fields included no I have also updated or leave request list detail and I have added the start time start date and end date those weren't there before as well as the employee object and the requesting employee ID so now when the admin is viewing the list of requests they can see what the request the start date on the end date of said request as well as the details of the person who has requested it we have made a similar modification to the leave request where we have made sure to include the employee information now a quick modification to the mapper and at this point it's optional because I want you to think critically not just do as I do but think about it we have a field called Date requested in the leave request domain object so that was created as it was modeled off the previous system now remember that we are refining the system and getting rid of some of the redundances and code smells and I think this is one of those code Trends because the date requested really is the date created so we already already capturing the date every record is created I don't have to put in date requested again and frankly we didn't do that in the Handler when the request went in so what I'm doing here though is I am actually doing a mapping or a custom mapping for a certain field so I'm saying that whenever you're mapping from the domain object to the dto looks in the dto or the destination and get the date requested field and then I want that to be mapped directly to whatever is in the date created field in the leave request domain object all right so once again that is optional but since you already have the fees I'm just showing you the power of automapper how it helps us to just in the background make sure that all the data is there it's relevant and at the right place now moving on to our handlers so I've made some changes in the leave request Handler and leave allocation handlers for both the list and the details so I'll start off with the list since that one I think has more changes than not so one I have modified the request to have this flag to say is logged in user meaning are we trying to get the leave request list for the logged in user or for an admin so in the Handler I'm injecting the HTTP context accessor as well as I user service I don't think those were there before no so I'm injecting them and anything else that wasn't there before now feel free to go ahead and replicate but then inside of the Handler what I'm doing differently now I am initializing the leave request list up top and I have another list for the dto that will be returned which in this case is the leave request list tto then I'm checking if the request says it is for the logged in user or not right so if it is for the logged in user I want to go ahead and get that user ID there I'm using my constant see how nice and clean that looks alright so I'm getting the user ID and then I have actually implemented another method to get leave request with details relative to the user ID so let's go to that method implementation so in the contract for I leave request I have two get leave requests with details the original one that we wrote together and this new one with the string user ID so that one with the user ID basically just adds on a condition where the requesting ID on the record is equal to the user ID being passed in we still include the leaf type details and send back that list now after doing all of that I use the user service to get the employee relative to the user ID that is there and then I do a mapping from the domain object into our detail then for each request object in the list of requests or details we're assigning that employees value all right so once again this would be if I am logged in as a user and I want to see my list of requests this is going to handle that now if the admin requests it it's pretty much the same as it was before where we just get all of them with the details and then for each request we're going to actually look up the employee on the fly right so whereas we know the employee because I am the logged in user so it's only one of me we don't know there are many different employees so for each request we're going to fetch that employee and put it inside of that and at the end of the day we return the requests likewise I'm doing a similar operation for the leave allocations where I am fetching all the allocations from the database have a similar method and pretty much this code looks the same way right so just the same way that we had the leave allocation leave request with details relative to user ID it's the same way that I have implemented a method like that for our leave allocations where the employee ID is the user ID and we have the same if statement we have added the same kind of flag to our request right so request as pool is logged in user and then we have the if statement if it's logged in then pretty much the same procedure as we just saw um relative to leave allocations however then I have get leave request detail so that's when you want one leave request so picture it when the admin sees the list of leave requests he or she needs to click on that leave request to then go to a screen to see is it pending is it approved or be able to approve Android or reject it at that time right so I have modified the get leave request with detail where I have putting this line to include the employee information so pretty much all the modifications so far are just surrounding the fact that we need to put in that employee information so since we've updated that request class we need to know let our endpoint or our Behavior reflect this new parameter right so on the get I'm going to pass in a Boolean is it the logged in user that we're after if it is well I'm defaulting it to false right so that's so you can put in a default parameter where if you don't provide a value then it's false right so regardless of its value we'll pass it into the request object and then the Handler will meet the decision like we just saw so I've done this in both the leave allocations and the leave requests Handler gets as usual once you update your API anything with the return type anything in the controller you want to rerun in swag and get a fresh copy of that client code now I'm going to jump back over to our client application and we're going to look at our contract so the next few ones that I want us to absolutely pay attention to would be the approve the request and to get the admin leave request list all right and we also need to get leave request by ID so at least those three need to be implemented right now so I have other methods there and by the end of this course they would be implemented but I'm not going to spend too much time going on the rabbit hole of trying to get every single feature in for this module we're just going to focus on the employee being able to ask for a leave and the admin being able to approve or reject it so after you have included those three methods in the contract we go over to the implementation so of course by now I'm sure you have updated your client code so everything that I have here should work for you so for the approved leave request what we're doing is taking int ID and the flag or the Boolean to say is it approved yes or no then we are going to formulate our request where we put up a change leave request approval detail and we pass in that approved and the ID and then we await the client calling change approval async where it sends over the ID and the request our get leave request is fairly straightforward it's just returning leave request view model we add our Bureau token of course which we also did in the approve leave request and then we go ahead and try and fetch from the get leave requests get async by ID and return the mapped version of leave request in the form of the leave request view model we'll look at that in a few once again next noteworthy method would be the get admin leave request list now I'm going to explain what I'm going for in this in the original application what we had done was we got all the leave requests and then we try to group them and then figure out is it for the total leave request is it for how many approved pending etc etc that's exactly what I'm doing here so I'm getting all the leave requests and notes this time I have that parameter is logged in user colon false I'm just naming the parameter this part is actually optional but I find it useful so that I can remember what the value really means in terms of the function call but I'm passing in false because this is not the logged in user this is the admin right so the admin is getting all the leave requests and then I'm just creating that model admin leave request view model and we're passing in the total number of requests how many are proved rejected and putting in the list of leave requests in general and we're returning that model all right so once again all our heavy lifting happens inside the service now inside our mappings configurations I have updated that to reflect some of the new mappings that we can expect so for a leave request detail to leave request VM there is a slight difference in the data type between the dates all right so on one side we have date time but then the dto that gets generated via our in swag code actually gives us a date time offset I'm not entirely sure why it does that but the solution would be that when we are mapping we just say four member date requested go ahead and map it from the requested dot date time and we do that for the start date and we do that for the end date and that actually will take care of that error so if you fail to do this if you want to test it you can comment these out attempt to run the code that would require mapping and then you would see that auto mapper error saying that the mapping is failing for the date related fields all right so you can do that for the leave request the leave request VM the leave request list detail to the leave request VM and then in addition to those new ones I also have one here for the employee where I also have created the employee VM which looks just like the employee ETO now inside the leave request view model file let's just review some of the view models at least the ones that are absolutely necessary for us to complete this activity so we have added the employee VM with employee inside of this view model so of course automapa will see any two properties of the same name it will try to map them right so it's implied that in the employee will map to employee from the detail to the view model right um we also have the admin request view model which we didn't necessarily look at before now so that has these fields the total request approve requests pending requests rejected requests and the list of leave requests so you can go ahead and make sure you have representation for that view model in your code so going back to our leave requests controller you see now that I have three new actions I have one for the index one for the details and one to approve requests so index that will take a model and this model will be of type admin leave request view VM or what is it calling the leave request service dot get admin leave request list all right so the administrator will see this page where once again those statistics and the list of outstanding leave requests will be on display our details method basically will be there for when they are seeing the list and they click on one of the items and then we want to go and fetch that leave request with all its details and return the view accordingly then we have the approved requests now the approve requests will basically say go ahead and approve the request it's at HTTP post so we're going to put a form on that page where we're going to call that passing that leave request ID as well as if it is approved or not so if they're approving or rejecting whichever one it will pass that in and then you'll see in how it goes over to the API to the Handler and what takes place before we Implement those views however I just want us to follow up the full extent to what happens when it is approved so I'm going to jump over to the updates leave request Handler which has undergone some amount of changes also and I'll walk you right through it of course you pause and replicate as you need to so we are now injecting the leave allocation repository in addition to anything else that was being injected into this file and the reason for that is we need to be able to deduct the allocation when there is an approval so what we're doing here is refactoring our handle method for this so I get the leave request firstly and then I say if we're dealing with the leave request detail then I want to run the validation because what was happening initially or the way we wrote the code initially the validation code was being run regardless of this being null or not now if the validation tries to validate a null then that's also going to throw an error and throw everything out so we're just validating our leave request dto when it is present and then if everything is okay we go ahead and do our mapping and our update now otherwise if it is a change leave request detail that is not null which in this case of approving it is then or it isn't rather then we await the leave request repository change approval status method passing in the leave request and the fact that we want it approved then I'm going to say if the request dot change approval detail that's approved that value if that is true right so all of this really evaluates the equivalent to true but of course when dealing with booleans we don't necessarily have to say equivalent to true we can just say if the Boolean right and we don't have to worry about another exception because it's it always should be it always should have a value so that's another update we can make to our dto because right now I think we made it nullable which now we think about it is wrong it should always have a value so I'm actually going to remove that Boolean and we can update our and swag client code accordingly but later on we can do that so I'm updating that detail to always be either true or false so if it is true then we get the allocation for the employee so VAR allocation is equal to get users allocations this is a new method so this new method once again you put it inside of the contract but when you implement it it's basically taking the string using the user ID and the leave type ID so we go and we say get me the leave allocation first or default async where the employee ID matches the user ID being passed in and the leave type ID matches the one being passed in so after doing all of that we pass in the requesting employee alongside the leave request so we got the lead request here we now have the employee who requested it and we know the leaf type courtesy of the lead request once again and then we're going to say get me the number of days right so we already saw that math in the creation or in the request rather how many days are being applied for in this situation you could make another decision you could decide to store the number of days in the database from the get-go or calculate it on the fly like we're doing now so that's up to you either way we get the number of days we go ahead and deduct the number of days from or the days requested from the number of days for the allocation and then we run an update for that allocation then return now in terms of our views that match our controllers we have created the index and we have created the details truth be told the index is a split copy of what is coming from the old code so if you have downloaded the Old Source Code or you can just find it on GitHub you can actually take everything out of that matching leave requests index page and place here I haven't modified anything any modifications that are needed would be due to naming differences for instance here I have item dot employee instead of item dot requesting employee outside of that though the code is fairly the same now for the details I have made some modifications because in the original code we had repeated this alert section Thrice and what we did was we said if approved then show this alert code with a different class name a different heading text else if it's true then show it again with right so instead of repeating this and that's another part dry don't repeat yourself so in refactoring you always want to say well something needs to be repeated at some point right or some operation needs to be redone but which one can I redo with the least path of resistance or which would be easiest to maintain in the long run so my refactoring of what was done in the original DTS page would be that I am creating two variables here one name class name one for heading text and then if the approval is null then I give class name and heading text their values if it is true I give them different values etc for else then I load the div with the alert one time where I dynamically pass in that class name and heading text because everything else inside of that alert is going to be the same regardless right so I say employee name and then I put in model.employ first name and last name the date requested is the date requested coming back from the model and then pretty much everything else is the same up until the last part where we're checking if it is approved or not so instead of having two link buttons as the original code had I have wrapped them in forms we already discussed why forms are far more secure so form method post is the action approve request and in this one I have the ID which is a hidden and it has a value for the mod lot ID also have another hidden that has the name approved and the value is true I repeat that feed for the reject except the value for the approved is false so when they click either of these buttons it's going to call approve request which is then going to get ID and approved pass that down we just went through what the Handler does with all of that information all right so we've been at this module for quite some time and this is usually the most difficult and time consuming module I have tried to reduce the time as much as possible um but then you know there's much more to do but at least you have the foundational concept so you can take it and carry on so let us just preview what this leave request will look like from the admin point of view when we click leave requests we see the list of leave requests so I've already approved and rejected one and that's what that code looks like and this one is pending approval and we see the start date the end date uh the vacation leave type the employee name everything is nice and you know spit out for us so if I click review we go over to the page where it says pending approval date requested and then I can approve or reject so if I click approve then it will redirect assuming that there are no errors and actually there is an error all right so the problem here is that I am using the code from the create in order to do the calculation which is completely incorrect because I should be using the leave request object and not request dot leave request detail right so let me just update that and we can retry that operation all right so let's try again and I'm going to click approve and there we see it's now approved now the problem that we are going to have to address later on is the fact that we have multiple operations being carried out against multiple tables but guess what happened a pirate happened and the other part didn't meaning this was approved but the deduction did not happen because we had a failure on that leg right so we actually successfully did the approval but then the deduction part did not go through so it did not get updated and what we would want to do is to do something like a roll back it should be all or nothing so if one part fails then everything should fail so that is where the unit of work kind of comes into play or at a database level we call it transaction so later on we look at all of those housekeeping issues with our application we have an application this big you have to look out for those things all right guys welcome back this lesson is inspired by the failure point that we saw when we were changing the approval status of the leave requests we saw we're a part of the operation was completed and the other part failed but then you know we need both parts to actually work before we can update the database so what we're doing now is setting up what we call a unit of work which basically says that I have all of this work to do I have all these touch points I'm going to do all the operations and then do one final commit to the database it will it will either be successful or not so what we had was each repository saving changes on its own so if this if there was an operation that required two repositories um to save and one save than the other field then we would have in consistent data in the database and we want to avoid that so I've gone ahead and set up this I unit of work contract so we know where the contracts live in our application persistence folder our unit of work it's in everything from eye disposable and it's basically just making reference to the three repository interfaces that we know of right so I leave a location leave request and leave type and it has a method that says save now its implementation lives in the same folder as the implementation for the other repositories so that is the persistence layer repositories folder unit of work so inside of this implementation we're inheriting from the unit of work we have our EB context being injected in all right and we have referenced all of the repositories so we have private fields for each repository so basically this file is acting like I register for the repositories that we have we want to maintain the unique repositories um sometimes you would actually see a unit of work where it's built around the generic repositories so each implementation would just be generic but then we because we have so many unique methods in all repositories we want to keep the unique repositories being referenced here so later on we actually have the public property that matches each and let me just break line so you can see it more clearly so the public I leave allocation repository it's going to be called leave allocation repository and basically we're just performing a git so we're seeing get me the private field and if it is no it's initialize a new instance of the leave allocation repository implementation and pass in that context that we injected in because remember that each implementation has that context being injected in all right so that is why we have to make sure we inject in the context and then we pass it along to each one so those three lines pretty much look the same barring the names and the types being referenced then we have a dispose method which is going to be called in the background where we just dispose of the context and then suppress the final garbage collection and then our task to save is going to have our save changes so in other words we'll be doing everything would be putting we'll be adding we'll be doing whatever it is these you know repositories have to do individually but then we're doing one final save all right so after you've implemented that or you've you know replicated all of this let's take a look at some of the changes that are required in the other repositories so let's start off with the generic repository before what we had were individual safe changes in the ad the delete and the update methods right so now I'm getting that green line because there's no longer any asynchronous call inside of these async tasks but we can address that later but my point is that I've removed all the save changes lines from these particular methods because we don't want them to save if we have to do multiple things we want to add something and delete something and do an update we want one final commit to the database All or Nothing per unit of work or in each Handler because remember the handlers are basically dealing with scenarios so we want the full scenario to be completed all or nothing so we've removed all the save changes from the generic repository as well as from any other individual repository that may have had a safe changes being used in there so like in allocations where the ad range I had the same changes I've removed that and in the leave requests we had the save changes being done inside of that method to update right to change the approval status so I removed all of that now with those removals we need to update our handlers to act appropriately so I'm going to jump over to the create leave request and I'm going to show you exactly what kind of refactoring would happen one we would have been interacting with two or three the repositories in this Handler so what I've injected I leave repository I leave allocation repository etc etc now we only have to inject our i unit of work and before I move any further let me just point out that we now have to register it inside of the persistent Services registration all right so the same place would have registered all the repositories we're registering our i unit of work so that makes it an injectable component all right so now we can replace all the individual ones with the i unit of work now you're faced with a bunch of red lines well now where you had the underscore leave type repository as the private field you can now replace that with unit of work dot leave type repository because you're giving it the same repository just through the unit of work so this is like a register for all repositories out of mid mention of that earlier so I'm just highlighting all of the changes that I would have made now that I'm using the unit of work um underscore unit of work for the leave allocation repository unit of work for the leave request repository and then when we have an operation that is augmenting data we do a save see that now while I'm in this create leave request Handler I just want to point out one other failure point that I saw in my tests and you probably encountered and I just want us to address it here that is when there is no allocation because I have tried to apply for maternity leave with an employee that doesn't have maternity leave so you have two ways of dealing with that one you could only you could filter that leaf types list only on um Leaf types that are allocated to that user so a user would never be able to apply for something they have no allocation for and frankly I think that that is a nice clean way to do it you just create a new repository call where you get that pointed list and you send back that list I think that's easy enough I however have made an adjustment in this Handler in the interim to say get the allocations remember we got the allocation and then we calculated the days requested and if the days requested exceeded then we added a validation result error right but what I'm doing here now is I'm seeing if the allocation is not so with the new version of C sharp you don't have to say e is equivalent to know you know you can say is no right so if this comes back as null then we add a validation result error for the leaf type ID saying you do not have any allocations for the sleeve type so that's that's a simple if else addition you can go ahead and replicate that or you could try it on your own to get the filtered list for that particular user who is about to request leave and only display the leaf types that they're eligible for whichever one works now let's jump over to the update leave request command Handler which is where we saw the real failure points that we're trying to address now with the unit of work so once again inject only the units of work into this Handler and you'll see that it's much more compact right and then each line you just have to say unit of word dots the appropriate repository and that the method now when we're augmenting the data remember that we said if the leave request comes in with the dto then we go ahead do our mapping call the update and then I'm going to call the unit of work to save all right later down if it was the change request approval and this was where we saw the fault it would go ahead and change the approval and then if it was approved then it would update the allocation and then this one worked but then this one failed so it was approved and the person's days did not get deducted that caused inconsistency so now this person would have gone on vacation for 10 days and come back and then they will come back and see that they still have 10 days and probably apply and nobody would notice so we want to make sure our system is not at fault right so we updated the change uh the approval status fine then if it's approved we update the number of days and then we save so if this fails none of this happens in the database now with this change and the unit of work being introduced it's actually a bigger refactor because you'll actually have to go into every single Handler that was dealing with augmenting data and one injector unit of work two probably change out the references to the repositories all of all over the place and then three make sure that you call the units of work save method know that you've made that huge refactor right and especially when you have done that to the leaf type command Handler another point of contention that will come up is our unit tests because remember at least we did the unit tests for the leaf type command Handler together and now you're changing the injection you're changing something about it so actually if you compile at that point you would probably get some errors in the test files because now certain things don't exist anymore and that's one and two the fact that you know the operation has changed in general we need to update our tests let's start off with the mocks because that's probably where you're getting the first error that the mock repo no longer exists or the mock repo is no longer off the type that it needs that's fine so what I have done is created a new mock file that I call mock unit of work and it's following the same Principle as the previous mock where where I'm just you know instantiating a mock of eye unit of work it's called get unit of work that's a method and I have mock uow is equal to a new instance of the mock unit of work no I have the mock leave type let me record that mock leave type repo that's what we were dealing with right so that's the test we wrote to test the leave types know that I am using the unit of where I have to mock the repository inside of the unit of work I already have the code to mock the unit of Mark the eye leaf type repository sorry right so I already have that method that method doesn't have to change at all right we're filling it with test data and we have done all of that now I need to get this Mark into the unit of work Mark so all I'm doing here is saying mock leave type repo is equal to calling that mock class and getting the leave type repository and then my setup now says that the leaf type repository will return that mock object then I return that mock unit of work so now in the actual test for the create leaf type Handler and I've just commented out some of the lines just to show you what exactly I've changed I've introduced a new field of type mock UI units of work called mock uow uow unit of work and then I have instantiated it inside of the Constructor by calling my mock unit of work dot get unit of work afterwards everything else Remains the Same don't align well for me 42 43 where I'm saying that the Handler is now a new instance that takes the mock unit of work as opposed to the mock repo as previously used and that object then everything else will flow so at least down in the tests we'll have to say mock unit of word dot object dot leave type repository get all and similarly mock unit of work dot object dot leaf type repository get all otherwise the tests will pass and then you're good to go so once again unit testing would show you failure points or potential failure points in different parts of your application just in case they are or they went through massive refactor activities that's really it for this activity where we're adding the unit of work I hope you see the value in it and we will continue with improving our application in a subsequent lessons in this lesson we are going to be setting up a global exception handling middleware for our API so what happens is that we had custom exceptions that we created from almost the start of the project we have been throwing exceptions at certain parts in our handlers however we have not necessarily told the API how it should respond when exceptions are thrown so of course we want to always gracefully fail if there is a type of exception we want to send back a code that is indicative of the type of exception for instance I have updated all my updates uh handlers to also throw a not found exception so up until now let me just correct this one so up until no I didn't have the code if you already had the code then that's good that's kudos to you right but we were throwing validation exceptions when the validation fails but then what happens if they record to be found was not found then we want a not found exception so I've added that under each check to see if the leave allocation is found if the leave request that's about to be updated is found and if they leave sorry the leave type there we go if the leaf type is found we just throw a not found exception right so throwing the exception is easy enough handling it is another thing so notice that there are no try catches and it would be kind of overbearing if it were to try and put the track catch in every single one so what we're going to do is set up an exception handling middleware at the API level because the controller uses mediator to call the Handler but we don't have any track catches here either so we're always returning okay but then there are times when the exception is thrown and then okay can't be thrown and then the API is literally just throwing some random response back at the client we want to make sure that we know what is being thrown so go ahead and create a new folder in the API project called it middleware and in that folder create a file called exception middleware so that's our class exception middleware now I'm just going to walk you through what this is going to be doing one we have error details so we have a class in that file in that other class called error details I'm just walking you through the simpler Parts first and error details basically just has the error type and an error message so at least we can always inform the client this is what went wrong based on the circumstance that we're faced with right now outside of that we have inside of the class for exception middleware we have a private read-only field called Next and that is of type request delegate so we instantiate that in the Constructor and then we have a method called invoke async so public async task invoke async and it takes a parameter called HTTP context so we've already kind of looked at what the HTTP context allows us to do basically it allows us to see the request the response everything with a whole workflow between client and server is stored inside of this HTTP context so this is going to be acting like an Interceptor it's going to try to say it's going to say do the next action that should be completed via the HTTP context that's basically what that is doing right HTTP context do your next action if there's an exception let's catch it and then we will handle it now let's go on to how we handle it so private task handle exception async we're giving it the HTTP context and the exception that was caught now we we are just saying that we want a response content type to be application slash Json because it's the API so we know that everything that we respond is going to be in the form of Json we're also setting a default internal server error HTTP status code so status code is defaulting to that which is 500. then we're going to say the result is equal to I know we want to serialize the object into a new instance of uh arrow with the exception message right so we're serializing all of this into the results now when we go on to the switch we're basically seeing what type of exception is this because exception is the base data type but then as we've seen we have our own exceptions we have the validation exception we have the let me go over the bad request exception we have the not found the exception so we can actually account for all of these um accounting for bad requests I'm not accounting for validation let me go ahead and update that so what we're doing here now is seeing tell me what kind of exception it is I know it's an exception about which type was it really was it a bad request was it an an exception a validation rather or was it a not found based on the one that it is we're going to change the status code so it's defaulting to 500 meaning if it was just an exception maybe it was a database level failure maybe it was a network failure that we can't account for then it's definitely a 500 500 means it's our system the the system that the API is using it's the system's fault however bad requests would indicate that you are at fault as a client because you sent me garbage data so I'm going to tell you it's a bad request which is a 400 there we go if it's a validation exception that's also kind of a bad request um because you sent me bad data but you can always look through and see what other code might work better for the type of exception right but then you always want to stay in the 400 range with error codes right so that's where we are so let me leave that alone so this can say as bad request and then not found the exception is a 404 meaning I couldn't find what you were looking for so 404. so if none of these was the case then we just break and that would remain as a 500. then we say respond with the status code and return with the result result meaning that whole message that was a part of the exception message so remember that when we are setting up our exceptions or throwing our exceptions from our handlers we're always setting the message and that message is what is getting serialized here and being sent back as part of that response now if you want it to be a bit more explicit because all we're doing is sending over arrow with exception message we could use our error details I could have said new error details and then error message would be the message and the error type could be something else so could say error type is equal to and then probably just say failure or error whatever it is so you can get creative I mean it's up to you but once again this is what they would get in the response whatever you put there so now that we have finished setting up that middle where we need to jump over to the startup file of our API and inside of the configure section we're going to tell it to use the middleware so I'm just going to do it right above everything else and I'm going to say app.use middleware exception middleware go ahead and add any missing references and there we go so we now have our middleware trying and catching globally and then gracefully handling how it responds to any client that is calling I just want to jump back to the implementation once again and I have a quick adjustment I don't know why I left this off initially so with the results for the validation exception we definitely want the exception errors to be going back in the body right so the validation message is one thing fine but then we want results to be equal to the the Json serialization of the validation of the errors right so once again you have many options on how to handle the situation so we're setting the exception message by default but we're overriding it in the case of the validation error to be the list of errors I want to say thanks guys for sticking it all to the end of this course with me where we didn't necessarily have a fully functional HR leave management system at the end of it but we have looked at some Advanced Techniques that I know you can take away and apply to your daily routines for the duration of this course we wrote code that was modular testable maintainable and reusable and we were sensitive to the solid architectural principles we implemented the cqrs and mediator patterns we looked at the best practices for separation of concerns we implemented an API we looked at how to secure it with JWT authentication and how to consume that and use that or advantage in a client application we have done so much together and I am very once again thankful for your dedication and your support and if you have any suggestions feel free to leave them in the suggestion box and I'm always open to feedback thanks once again and have a great one [Music] thank you [Music]
Info
Channel: Trevoir Williams
Views: 68,220
Rating: undefined out of 5
Keywords: clean architecture, .net, asp.net core, clean architecture cqrs, clean architecture .net, clean architecture setup, asp.net core web api, asp.net core mvc, asp.net core tutorial, software architecture full course, clean architecture example c#, design patterns in microservices, clean architecture with asp.net core 7, asp.net core 6, asp.net core 6 tutorial, software engineering, trevoir williams, codewithtrev, clean architecture explained, clean architecture example
Id: gGa7SLk1-0Q
Channel Id: undefined
Length: 425min 22sec (25522 seconds)
Published: Mon Mar 13 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.