ASP.NET Core MVC 3.1 Projects (Full Course)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello in this course you will learn asp.net core 3.1 mvc by building projects the course will cover how to use asp core mvc to make websites and how to create and consume restful apis plus there are standalone lessons after the projects with topics that didn't fit in with the products and of course there is much more along the way if you like the content please like and subscribe to support the channel and be notified when new courses and tutorials are published okay let's get to it in this video i'm gonna go through the projects that are created throughout the course so first we have this cms and shopping cart project okay so we have a cms here with pages so this is the home page and contact and services and about and of course you can add as many of these as you want and you also have products here so a shopping cart and you have to actually be logged in to access this part so i'm gonna log in as let's say drawn okay so now if i go to all products i can and products by category as well and if i log in as admin now i have this admin area link here so i can go to the admin area and here i can manipulate pages and categories products users and user roles okay so all the crowd operations create read update delete and let me again login as a regular user such as john and add something to the card so let's say add this and this and you can see here the cart updates so go to view cart and here's an overview where you can also add or subtract or remove products and check out access to paypal checkout so if i click this so now i'm taking to the paypal sandbox checkout here the products and so on okay i'm gonna go back to the project so the card has been cleared and this is a brief overview but there's a lot in this project okay so it's a big one and let's go quickly through the rest stuff as well so i have the api here and this works with the pages from this project okay it uses the same database and the pages table and i can go to a particular page as well and see that and i have all the crowd operations for the api so create read update and delete and it also uses put and delete methods or requests actually and here's the client that consumes this api so it's just the pages and you can also do crotch stuff from the client so if i go to edit i can edit here and i can delete as well and i can add new okay once again this is a brief overview of the project and there's actually a lot in these projects so i really hope to see in the course in this video i'm gonna go through the software that's used in the course and that software is visual studio community edition but the preview version is gonna be for me so if i go to help and about here you can see that it says microsoft visual studio community 2019 preview okay so it's the same as the regular version but it contains the latest features since currently regular visual studio doesn't support asp.net core 3 and preview does so you can use either one as long as it supports sp.net core 3 and to get the preview you can simply google visual studio preview and this link right here and here it is okay so it's the same thing as i said as the regular version it just contains the latest features which is asp.net core 3 in this case so if i search for visual studio installer on my machine you can see that i have both the visual studio community 2019 and the preview version installed but as i said i'm going to be using the preview one and if i go to modify just to show you what i have installed i just have asp.net and web development checked here and let's see data storage and processing okay so those are the two things you need to have installed for this course okay and that's gonna be it for this video see in the next one in this video i'm gonna create a new project in visual studio so i'm gonna click here okay so in here i'm gonna go to create a new project and i'm gonna choose sp.net core web application and click next and i'm gonna call it cms shopping cart location is fine for me solution name as well and click create and here i'm going to choose asp.net core 3.1 so just choose the latest one that's available and i'm gonna choose here web application model view controller okay and no authentication and i'm going to leave this configure for https and click create okay so here it is i'm gonna close this file that's open and if you get prompted to accept something regarding https just accept it i already did all that so i don't have anything popping up so anyway here's the project and the last thing i'm gonna do in this video is add the project to source control so i believe that git comes with visual studio integrated git i'm not 100 sure but i believe it is but me i always install get regardless of visual studio so i had it when i installed virtual studio but once again i believe it comes with visual studio so anyway to add the project to source control i'm gonna right click the solution here and say add solution to source control okay and now here in team explorer i have my project and now i'm ready to move on okay that's gonna be it for this video and in the next one i'm gonna go through the files and folders of an asp.net core mvc3 product student in this video i'm gonna go over the files and folders that make up an asp.net core project so let's see what we have here we have these dependencies and here you will be able to see the packages that you download for the project then there are properties with launch settings.json so here you can change the environment and the port number and so on okay then there's this www root folder which contains static files such as the favicon the libraries you use js and css folders images and so on so all the static files controllers is for the controllers models is for models and viewers is for viewers and the viewers folder contains some files and folders of its own when you create a project with the mvc template as we did and i'm going to go through this during the course but the views are here does the point and app settings json is where you can have some configuration most notably the connection string for connecting to the database goes here program cs is the main entry point for the program so there's this main method here and the startup cs file is very important it contains configuration so there's this configuration configure services method that is which registers services or dependencies and configure method which is used for some configuration and it also contains routes routing okay and we're gonna go in depth with all of this as we move along with the course okay so that's it for the overview and lastly to actually start the product i'm going to open chrome and there are two ways of starting a project either with debugging or without i usually start without debugging but you can use debugging if you want to use breakpoints so anyway as i said i usually start with debugging which is what we'll do now so i'm going to press ctrl f5 and here is the home page as it is right now so you should be saying this as well hopefully you do see this and there's this iis icon here as well that i have which means the server is running and now i can make changes here in visual studio in the code and i don't have to restart the application every time because it started without debugging okay so it's just gonna keep on running and i'm gonna have it like that for most of the time okay that's gonna be it for this video see in the next one in this video i want to go over why this page appears here when you first start the application okay so when you create a project with the mvc template as we did you get in the controls folder this home controller and in the views folder you get the home folder and shared in these two files as well and i'm going to go over shared and this to files later on but the point now is this home folder in views and the home controller and in the models you get this errorview model but that's not really important so anyway in the home controller we have this logger field and the constructor and then this index method okay so this index method is actually what's being displayed here does the request has handled and that's what the c is in mvc so the controllers and the controllers handle requests okay so when you go to the root which is this domain for me you might have a different port but anyway when you go to the root you get this so the default request is this home controller and the index method or action as we call it in asp.net okay so why is that so that's because it is defined so in the startup cs file down here in the configure method here are the routes okay so we can see that there's one route defined for us when we create the project with the mvc template which is this one right here so its name is default and this can be anything but the point here is the pattern so the pattern goes controller slash action and action is a method of a controller slash sum id which is optional okay because of this question mark that makes it optional and as you can see here this says controller is equal to home action to index which means those are the defaults so that's why the root domain points to home controller and the index action by default okay so let's see for example here what else we have we have this privacy action so if i click here to go to privacy i go to slash home slash privacy okay because of the route again which is some controller slash sum action with the defaults being home and index so if i go to privacy i actually go to slash home slash privacy okay and if i let's say change this default action here to be privacy instead of index then if i go to the root i'm actually going to get the privacy policy page and not the index page okay and i can still go to home if you just click but now the url is slash home slash index it's not just the root path the root is privacy policy because they said so here okay anyway i'm gonna change this back to index and we're gonna get more into routing as we move along with the course but i just wanted to explain in this video why that default page is there and one last thing i want to mention is we have the home controller and we also have in the views folder and this views is v in mvc so views which is what you see was displayed it has this home folder which corresponds to home controller without the controller suffix and it's like that in asp.net so whatever controller name you have you have that view folder as well without the controller suffix and in here we have the index html and privacy cs html which are html files that contain that can contain c sharp code as well with razer and razer is the templating engine of asp.net okay so we have this index method which returns a view and if you don't specify a specific view in here as a parameter it is assumed that you want the same view as the method name so index in this case okay so index method and index view in home folder and privacy method and privacy view file in the home folder and lastly the models so there's this air view model now which doesn't really matter much the point of models and the models is the m in mvc they can contain various functionalities but the most basic one is that they represent the data you work with which corresponds to the data in the database so for example in asp.net core you would have classes here in the models folder that represent the tables in the database and as i said the these models can also contain other functionality depending on the platform you use if it's sp.net or let's say node or java or php or whatever but anyway the most basic functionality is the data you work with and you're gonna see that in action and it's gonna become clear in case you don't have experience with that already so anyway that's gonna be it for this video you should understand now why we have this page right here as the root page on the root domain and you should understand also the basics of routing but we're gonna get more in depth into all of this and more as we move along with the course okay that's gonna be it for this video see you in the next one in this video i'm gonna go over the view files that are generated when a new asp.net project with the mvc template is created so this shared folder with its files and view imports and you start okay so let's go back to the root here and this welcome page so as we said in the last video in the home controller there's this index method which is responsible for returning this page okay but this index method actually just returns the view called index right which is in home folder and index file right here so there's only this in the index file and this is razer's syntax okay when you see this at and curly braces or just at its razor so this is some razor here which i'm not gonna get into too much now but there's also this tech center div with well commander p which is this right here okay but we also have all of these other things such as the navigation here and the footer and in chrome if i press ctrl u i can go to the source and we can see now that we have all of this and yet only this html is returned by the index view so how come does the case that's the case because asp.net supports having one main layout for the application and then these smaller view files so to speak are injected into that main one okay so the main one is in shared and underscore layout so here it is okay so this is the main layout file which contains most of this stuff right here here's the header and the navigation and so on and this render body here is where the smaller view is injected from an action method okay so there's this main here with render body and if we look here here is that main and it ends here and here is the div with html from the index view so that's how it works and this shared folder contains files that are shared throughout the application does the main layout file and it's defined to be used as the main file in view start underscore view start that is so here it is there's this razor syntax here and it says layout is equal to underscore layout which is going to be looked for automatically in the shared folder okay next there's this underscore validation scripts partial and this just contains jquery validation scripts which are in ww root and lib and um jquery validation right here and jquery validation unobtrusive and this can be injected into any view and we'll see how that's done later on so that's not being used right now and there's also this error view file which doesn't really matter it comes with the mvc template and you can see up here it says at model and air view model which is this class right here errorviewmodel.cs and i'm going to explain how this works later on right now it doesn't really matter and it's not important at all for the project and it's not important for the fundamentals of any project in any case unlike the layout folder and the view imports mustard which are really important and are a part of every project so finally this view imports it contains the using statements and the tag helpers as well so this isn't going to make much sense right now but because of this using statements here let's say this error cs html file it says here at model air view model and this air view model class it lives inside of the cms shopping cart dot models namespace right because it's in the models folder here and because in view imports that namespace is imported here with using then you don't need to use the fully qualified name when specifying the module for a view and again i'm not going to go into specifying the model for review right now but it just exists here now so i might as well mention it so if we didn't have that using statement then we would need to use the fully qualified name here okay like so and models and air view model but because there's not using there in the view imports we don't need to use the fully qualified name for classes in this namespace and we can add more namespaces here as well like so okay and the tag helpers here at tag helper is used to support tag helpers and we're gonna get into tag helpers later on there's a bunch in sp.net such as form tag helpers anchor tag helpers and so on and the point is that you need to have this line here in view imports which is there by default in the mvc template so you need to have it there in order to actually use the tag helpers okay and uh i didn't mention uh one file when i went over the files and folders of the project which you don't see here to say it you have to right click the product actually and go to edit project file so here is that name of the project dot cs prog file and it just contains the target framework and packages you use so this file is going to change with the packages as we add more packages okay and i also didn't mention in that video uh which you can see here that you get with the mvc template you get bootstrap and jquery automatically with the project and the jquery validation as well so this is the latest booster booster 4 and jquery and validation which is all really good in my opinion since i use all of those in every project i work on regardless of the technology used if it's asp or not so i just find that a great thing to have automatically that's support for both drop and jquery and jquery validation okay that's gonna be it for this video see in the next one in this video i'm gonna get started with creating the database so first of all i need to get a few packages so i'm gonna go to tools and no get manage nugget packages for solution and browse and i'm gonna search for sql server and i want this entity framework core sql server click the project here and install accept okay it's been installed and i also want to get the ef core tools so i'm going to search for tools and entity framework core tools is what i want so install that as well accept that should be installed so if i go now to dependencies here and packages now i have these packages here which i didn't have before and you can see here the install packages and also if i right click the project and go to that the project that is not the solution and go to edit project file if you remember now i have the sighting group here with the packages that i just installed so this file has been modified okay and let me just collapse this folder and the dependencies as well so now i need to create a database context class that's going to represent the actual database so to do that i'm going to create a folder in the project so right click the project and add folder and i'm going to call it infrastructure like so and some people create this context class in a data folder i mean it can go anywhere you can have it in the models folder as well or wherever but i don't want to have a folder just for one file so i'm going to use this infrastructure folder for all the custom things they do such as this database context class and custom tag helpers custom validation and all that good stuff we're gonna do as we move along with the course so anyway in the folder i'm gonna right click it add and add class and again you can call this class basically anything i'm going to call it cms shopping cart context which is kind of the norm so the product name and context add that okay here it is and this is gonna extend db context and we need to import this so i'm gonna say using microsoft ef core like so and in here we need the constructor so i'm gonna say ctor and double tab and in here i'm gonna say i'm gonna pass that as db context options and the type is gonna be cms shopping cart context and call that options say base and options okay and there's not going to be anything in the constructor but we need to call that base constructor as well that's how it works save that file so so far so good lastly in this video i'm gonna commit my changes so i'm gonna go to team explorer here and changes and i'm just gonna say db here and commit all and save okay and i'm not gonna be committing any more on video because i'm gonna try to keep the videos as short as possible and i'm gonna commit after each one and you don't need to commit after each little thing you do it's up to you i showed you how to do it so whenever you make a change you go to team explorer and click on changes if you haven't and you're going to have the files here that are changed so now if i write something here you can see it's appearing here okay and i'm gonna get rid of that save and now it's gone because there is no change okay that's going to be it for this video see you in the next one in this video i'm going to create a page model and that model is going to serve as both a dto and the view model and dto stands for data transfer object and it represents the table in the database and the view model is a model that is used with the view to represent the data that's used within the view and you'll see how that works later on so anyway before i create the model i'm just going to get rid of the stuff that i don't need such as this air view model here delete that and home controller as well okay and home folder in views and this air view file as well and now i'm gonna build the project to see if it's all good and for me let's see the shortcut is f6 i believe i changed that i think that's not the default one but i'm not sure check what it is for you anyway for me it's f6 so i'm going to press f6 and one build failed it failed for some reason let's go to error list the type for namespace models doesn't exist let's see okay i'm gonna create that model in that namespace now so it's gonna be good let me just right click modes and go to add class and i'm gonna call it page okay so now i'm going to specify the properties that i need which are going to be the columns in the table so prop and double tab and id shift enter to go to next line and probe double tab string and this is going to be called title and again string and slug and another string content and finally end sorting for the sorting order okay save that looking good and let's build again and see if it's okay now okay now it's all good it says here one bill succeeded so anyway back in the cms shopping cart context class after the constructor i'm gonna say prop double tab and this is gonna be db set of type page and page that is and let me import this so cms shopping cart models and i'm gonna call it pages so in this way i'm gonna be able to create and access the pages table in the database and the type is page which means the table is gonna contain this field right here okay those are gonna be the columns and i called it pages and this can be called anything here and by the way since i have an id here a field called id that's going to be recognized automatically as the primary key once the database is created okay save that so far so good okay that's going to be it for this video and we're going to do the migrations in the next video see you then in this video i'm going to use migrations to create the database and migrations is a set of tools that lets you create and update the database based on your data models so anyway before i do the actual migrations i'm gonna create that service or register the service for the project so to do that i'm gonna go to startup and here i need to register that db context service or dependency and that's done in the configure services method so after this services at controller with views i'm going to say services and add db context of type cms shopping cart context and let me import this and then i'm going to say options and fat arrow and options use sql server and let me also import microsoft ef core let's see okay here it is and in here i'm gonna say configuration and set actually get connection string and the name is gonna be cms shopping card context so i'm just gonna copy and paste that okay save that so once again you register your services and dependencies in the configure services method also if you're new to dependency injection especially in asp.net be sure to watch the dependency injection video in the standalone section of the course the standalone lessons section okay so anyway let's continue with this we registered the db context here and now we need to create this connection string and the connection string goes in app settings json and in your course files which you can download from the last lecture in the course you have among other things the connection string so i'm just gonna open that and copy it and have a comma here and paste it okay and this is ready string that's just missing the database name here so i'm going to call it cms shopping cart context and you can call it anything save that and that looks good so finally now for the migrations open package manager console either from down here if you have it there or if you don't go to tools and nougat package manager and package manager console and here i'm going to say add dash migration and i'm going to call it initial create and you can call it anything but i'm going to call it inner create hit enter okay and you can see here that now we have this migration folder and there's the file with the timestamp underscore initial create and it's open here it open for me by default and it contains this up method which creates the tables and right now we just have that pages field in the db context and here are the fields which are going to be the columns so id titles log content and sorting okay so you can see that the end fields so the id and the sorting are not nullable and the strings are nullable so to make strings not nullable i'm actually just gonna delete this whole migrations folder so delete it okay and i'm gonna go to page cs and for the title i'm gonna say square brackets and required and import data annotations and i'm going to say the same for the slug and the content as well and these data annotations can be used for model validation as well when submitting forms and so on but in this case right now they're gonna make the columns not null in the database in in this table okay so once again i'm going to go to packet measure console go up and just redo the migration okay here it is again and you can see now that the titles login content have nullable as false so that looks good and now i'm gonna say update dash database hit enter okay it should be created hopefully to view it i'm gonna go to sql server object explorer right here and if you don't see that go to view and here it is sql server object explorer and local db ms sql local db databases and refresh and here it is and if i expand and open the tables as well here's the migration history and the pages table based on our model so with these columns let's see i'm gonna right click it and go to view designer and you can see that the id has a primary key the titles login content are and virtual and id and sorting are ends and no nulls are allowed okay so it's all based on the model which is great okay that's gonna be it for this video see you in the next one in this video i'm gonna see the database or the pages table to be more specific so anyway in the models folder i'm gonna create a new class and i'm gonna call it see the data and have a method in here public static void initialize we'll call it and i'm gonna pass here i service provider and call it service provider and this i service provider is used to get registered services so in here i'm gonna have a using and save our context and i need that cms shopping cart context here so i'm going to say that's going to be equal to new cms shopping cart context and let me import from infrastructure and i'm gonna say service provider and get required service and for get required service i need to import this dependency injection okay so this get required service is going to be of type db context options which is itself going to be of type cms shopping cart context and import ef core as well and just have parentheses here oops like so okay so finally now in here i have access to the database so first of all i want to check if there are any rows in the pages table because if there are i don't want to do anything so i'm going to say if context pages and you can see i automatically have that pages property here which represents the table any so if there are any pages i'm just gonna return otherwise i'm gonna add some pages so i'm gonna say context pages and add range and in this range i'm gonna say new page and i'm gonna have the title as home and slug and i'm just pressing control space here to get suggestions by intellisense so slug is gonna be home and by the way the slug is a url friendly representation of a title okay so let's say actually we'll see in a minute an example of that here it's kind of the same but when you have for example multiple words you can't have that in the url you need to have a slug but anyway we'll see that in a minute so let's finish this content is gonna say home page and sorting is gonna be zero okay comma and let me copy this so i'm gonna highlight this whole new page and ctrl d bring that down and this one is going to be about us so now this log has to be a url friendly version of the title you can't have this in the url so this log is going to be about us or lower case and the content is going to say about this page and sorting is going to be 100 and highlight control d again and this is going to say services and services here and services page and one more control d and let's say contact so contact contact and contact page get rid of that last comma and finally after this i'm going to say context and save changes like so and they just did the shift enter here to get that semicolon at the end of the line or the statement and that looks good so now to actually run this method i'm gonna go to program cs which contains the main method which is the entry point okay so here i'm gonna have a variable var host and that's gonna be equal to create host builder args build and i'm gonna say host run and in here i'm gonna run that initialize method so i'm gonna say using and var scope is gonna be equal to host and services and create scope and import dependency injection again and here i'm going to say var services and that's going to be equal to scope and service provider and then i'm going to have a try here and in cash i'm gonna have exception x and just throw x and i'm gonna try seed data and let me import that so from models and initialize and pass services actually i don't even need this x here i can just throw like so okay looking good so hopefully this is going to work let me build so f6 for me for you it might be different once again go to build and check what shortcut it is to build solution for you f6 for me okay there are no errors and control f5 to run it and i get this localhost page can be found because we deleted the home controller it doesn't exist but still the table should be seeded so if i go to pages right click view data and here it is okay great that's gonna be it for this video see in the next one in this video i'm gonna get started with the admin section of the website and for that i'm gonna create an area and an area is kind of like a mini mvc application within the main mvc application so you don't have to do that but i think it makes sense for the admin area and let me just click here to disable this show files anyway i'm gonna right click the project and go to add and there should be area here but there isn't so i'm gonna create a folder called areas and that's missing after the last update i believe but anyway now if right click and go to add here it is so area and i'm gonna call it admin like so okay it's ready now and as it says here we need to add this route for the actual admin area now because the one we have is not sufficient for the admin area so i'm gonna let me actually copy this and go to startup and route down here and above the defined route i'm gonna paste what i just copied and this is gonna be endpoints now and the map controller out for some reason this scaffold rhythm is still has the old areas from asp core 2 but anyway and this is supposed to be pattern and this looks good i'm gonna this is actually supposed to be map controller out okay so i'm gonna leave this as it is this looks good so default is home and action index that's fine i mean i'm not going to have a home controller but anyway this will do so that's done and now in areas admin as you can see i have that mvc application within the admin area now so i'm gonna get rid of the data folder and the models as well i'm gonna be using models from here so for the controller i'm going to right click and go to add controller and show this empty mvc controller and i'm going to call it pages okay so here it is and controllers in mvc are c sharp classes that extend controller okay so we have this index method when we create a controller and just to test it out i'm gonna say that it returns a string and just return here test like so and one more thing to do is because this is in an area i need to set the area attribute on this class so i'm gonna say here area and admin okay save that so now if i run the project control f5 to start without debugging okay so here's the root page which doesn't exist and i'm gonna go to admin slash home admin slash page is actually not home and here it is test okay great so far so good that's gonna be it for this video see you in the next one in this video i'm gonna modify this index method to return all the pages because right now is just returning a string so anyway first of all in this controller i need to get that database context so that's a dependency i need and i need to inject it into this class so the way you inject dependencies in controllers is via constructors okay so first of all i'm gonna have a field here i'm gonna say private and read only and cms shopping cart context and i'm gonna call it context and import this from infrastructure and now i'm gonna inject it in the constructor so i'm gonna say ctor double tab and just copy this same shopify context and say here this context is going to be equal to context okay and now i can use that context and methods or actions so for the index method first of all i'm going to say that it returns an i action result and this i action result is kind of uh catch all for returns so it can return views redirects and so on anything basically you can be more specific so let's say if you want a redirect you can say this returns let's see redirect result like so but i action result is gonna be able to return more or less anything and i want to make this method async asynchronous so i'm gonna say public async and then have this be a task with the type of i action result okay get rid of that return there so i want to get all the pages so i'm going to say i queryable of type page and import this from models and call it pages and i'm gonna say here from p in pages in a context pages that is and order by p and sorting so you can see i have that intellisense support and select p and i want to turn that into a list so i'm gonna say list page and pages list i'll call it and that's going to be equal to a weight and pages to list async okay and i need to import ef core and finally return the view with that pages list save that okay looking good that's gonna be it for this video and i'm gonna create the view in the next video see you then in this video i'm gonna create the view for this index method so to create the view of course i can go here in the views folder and add a folder and so on but i'm not gonna do that i'm gonna right click inside of the index method and go to add view and view name i'm gonna leave as index so same as the method name the template here is a template you can choose to get some html rendered automatically which i will use this is a really good thing so you have create delete details edit and list or empty without model so i'm gonna use list and if you use a template you need to specify a model class so it's gonna be page in this case is gonna be based on the page model and i'm gonna have reference script libraries and use a layout paycheck so i'm gonna click add let's see what happens okay so here it is i have the model here and then view data title and now i have some html so this h1 and the table so let me now just go to that url and see what is gonna display so i still have that is server running here as you can see from the previous video so i'm just gonna refresh this page and here it is so as you can see just like that we have a list of the pages there's no layout here or anything so if i control you you can see that literally there's not even an html tag here open html and so on it's just the table with th1 which is fine for now so back in the method here i just want to mention that you might remember from before even though i'm not specifying a view name here it knows since the view name is the same as the method name it's going to look for that automatically okay but if i change this index to let's say apples and refresh now it's not going to find it but you can see where it's trying to find it so it's trying to find it in areas admin views pages index and areas admin views shared index and finally in views shared index okay but i can still have that view named apples but here now i need to say apples as the first argument and then pass the date i want to pass so save that and refresh and i can see that view again now because i'm specifying the name but i'm gonna get rid of this and rename this back to index save that and refresh just to make sure it's all good okay great that's going to be for this video in the next video i'm going to add the main layout for the admin area and in a video after that i'm gonna go through this view so of course i will go through this view don't worry about it let's just add the layout in the next video okay see you then in this video i'm gonna add the main layout view for the admin area and the other view files as well the shared ones so to do that i'm gonna go to views in the root of the project and copy this shared folder and paste it in views in the admin area okay and view imports and view start as well so copy that and paste it in viewers in admin okay so let's see now if i refresh the page and now as you can see it's using the layout so that's great i just want to change it up a bit for the admin area so here i'm gonna say admin area in the title and this one here is gonna say home and target blank and i'm gonna get rid of this asp area controller in action and just have a regular ahref that's going to point to forward slash which is the root okay and let's see here in this ul i'm going to get rid of this secondly and i'm going to modify the leaders there for the pages so you can see now those tag helpers in action anchor tag helpers in this case so you can specify the area the controller and action and it's going to map that to the appropriate controller in action and create a proper url so for this i'm gonna say that asp area is admin and controller is pages action index that's fine and this is gonna say pages save that and let's see the rest i don't really need this footer in the admin area so i'm going to get rid of that and i'm going to leave the rest so jquery and bootstrap.js and site.js and this render section script is when you add some javascript to a view you can add it to the script section and then even though it's in that view such as this index for example down here let's say even though it's there it's actually going to appear at the bottom of the page via this render section scripts and you'll see how that works later on okay so anyway this looks good here we have site css so custom css file that comes with this mvc template and boost up css and it's all good so refresh okay home and pages so if i click home i'm taking to the root and pages links to pages controller and index action so that's all good and finally i want to go into the index view and i'm gonna go through this file in the next video but now i just want to get rid of this cms shopify models here that's not needed because in view imports are using that namespace here so you don't need to have it here as well it's redundant okay let me just refresh to make sure it works still and it does okay great that's gonna be it for this video see in the next one in this video i'm gonna go over this index view and explain what's going on so the first line here at model it tells the viewer what data specifically to work with what data is available to work with okay so whenever you see this at it means it's razer and the razer is the templating engine of asp.net and it enables you to write c sharp code within the views that's why the extension is cst html and not just html okay so in this case it's innumerable page but it can be just page or any single model or a string or whatever okay so next is this right here this view data is one of three ways to pass arbitrary data from you to view or more commonly from an action method to a view so there's view data there's view bag and temp data so this one is view data with the key of title and value index and that's used in the main layout here okay so that's how you can pass it from you to view so here the title is index dash admin area okay so index because it says index here so that's that now let's see i have this create action here and let's see where that points to so if i hover over it you can see in the bottom left it points to slash admin slash pages slash create so if there's only the action specified as p action and that's a tag helper anchor tag helper so if only action is specified it's going to automatically assume that you want the default controller and area for that view where it is in this case it's admin pages which is correct okay next are these ths and this here isn't really needed like this you don't need this c sharp code here this is only needed if you want to have a different name here than the name of the field so now it's model id model title and so on and we have that here okay and that's coming from models page so these are the names of the fields but let's say you want to display a different name for a field you can specify that here in the model and then use this code to display that name so an example would be let's say here instead of the title i want to display fruit so the property is still title but i want to actually display fruit the word fruit so i can say here display and name actually this is supposed to be name equal to fruit string like so save that and let's see now if i refresh and as you can see now it says fruit here so that's the only use for that i'm gonna get rid of that here and i'm gonna get rid of this c sharp code here because it's unnecessary i don't like to have a c sharp code where i don't need to but that's a personal choice you can use this if you want and while i'm here i don't want to have all these fields listed id and so on i just want the title the slug and these actions here edit delete edit details delete so i'm gonna get rid of this one and these two and i'm just gonna change this to say title just like so just plain word and the slug so no c sharp code okay and here i'm gonna get rid also of those tds i don't need so id and content and sorting and i'm gonna leave this okay so back to the model here you specify the model with at and lowercase model okay but you access it in razer with the uppercase model so this here if you hover over it you can see it's the innumerable of page so that's how you access it and it's looping through that ionumerable and here also we have too much of c sharp code in my opinion we can simplify this and just say item and title here and here as well just item and slug and you can see that intellisense is working here so that means it's all good and it's all connected properly so to speak so title slug and these actions here and these are all the action links this is how it used to be i don't know why they still have that in core now but i'm not gonna use that it's ridiculous i'm gonna use the new anchor tag helpers which are much better so here i'm gonna have an a and i'm not gonna have the ahref i'm gonna have sp action so edit this is gonna point to the edit method which doesn't exist yet in the pages controller but well and i'm also going to say sp dash route and then specify the route parameter which is going to be id in this case oops like so and i need the id of the page here so i'm gonna say add for razer and item and id and i'm gonna say edit here so i'm saying id here because of the route okay so if we go to the startup cs file i'm saying here that the third parameter of the url is this optional id so that's why i'm saying id here here that is and i'm gonna need that to get the actual specific page to edit so i'm gonna have a pipe here and just ctrl d twice to duplicate that line get rid of this one and this pipe as well and this one is gonna say details and details and this one is gonna say delete so it's gonna point to delete and it's gonna say delete here as well save that okay refresh f5 refresh the page to see what's up and here it is so titles log in these actions here and if i hover over them i can see that they point to slash admin slash pages edit slash the id of the page details the same just the details action and delete as well so it's all good okay so to recap you specified the model with at model like so and whatever the model is and you access it with the uppercase m in model okay that's going to be it for this video see in the next one in this video i'm gonna create the details action method for this link right here so we can view the details of a page okay so first of all i'm just gonna have a comment here and say get because this is a get request this method handles the get request and this is gonna be slash admin slash pages okay and i'm gonna copy this whole thing control d and this is going to be slash pages slash details slash some id so i'm just going to have five here and this is going to be called details the method and i'm going to have the id here and id which is that route parameter okay so that's uh let's see this right here and from the url it's this right here okay so to get that specific page i'm going to say page page and that's going to be equal to a weight context pages first or default async and here x x id is equal to id so where page id is equal to this id and i just want to make sure the page is not null so if page is null in that case i'm going to return a not found otherwise i'm going to return the view with the page save that and now i need to create the view so i'm going to right click inside the method add view view name is going to be details so same as the method name and i'm going to use a template this time details model class is going to be page and reference script libraries and use a layout paycheck add okay so here it is i'm going to get rid of this fully qualified name here have just the page title detail that's fine i'm going to get rid of this h4 and thr i'm just gonna have details here and i'm gonna leave these names of the fields as they are i'm not gonna modify them otherwise i can do for example just this but i'm just going to leave it as it is it doesn't make a difference so we have the model id the title slug and everything else and down here we have back to list and the edit link and i'm just gonna copy from here this edit link from the index and paste it there get rid of this action link and this is supposed to be model okay so if you remember from the previous video you access the model with uh upper ksm so model id and you can make sure it works with intellisense so at model dot and here are the properties or if you're not seeing them for some reason control space okay and id save that and let's see now if i go to details for home and here it is id title slack content sorting back to list if i go to let's say services okay great that's going to be it for this video see in the next one in this video i'm gonna create the create method for creating a page and the view for that so down here i'm gonna let me just copy this whole thing so ctrl d and get rid of the whole body and this doesn't have to be async because it just returns a view and the comment is going to be slash admin slash pages slash create like so and it's going to be called create and nothing in here and this is just gonna return the view shift enter to place that semicolon at the end okay so now to create the view right click the method add view it's going to be called create the template is going to be create as well so create model class page and reference script libraries use layout add okay so here's the view again i'm going to get rid of this fully qualified name here and just have page title create let's say create a page and here as well get rid of this h4 and thr save that and now because we have a form here and we had those reference script libraries checked we have this section here now section scripts and this await html render partial sync is one way to render a partial view and we're going to get into partial views later on but the point now is that this says section scripts and it contains this which is this file so jquery validation scripts and because it's in section scripts it's not going to get rendered in this view it's going to get rendered in the main layout and down here render section scripts okay which is uh really good so let's see what we have here now we have a div class row call md4 i'm going to change this to 10 save that and the form and now the form tag helper is being used here so sp action create and this is going to be it's going to have the post method by default so you don't need to specify its post if you actually want this to have the post method so the action is going to be create in the admin pages controller okay and this devsp validation summary is used to display the errors validation errors so this can be model only which means it's going to display here or it can be all let's see actually control space so all model only and none and all would display the errors on top of the form as well and you have none which isn't going to display anything and i'm going to just have this as model only and now we have this group form group divs so just boost your classes and let's see what we need here so this id we don't need and let me just space this out a bit the title we do need the slug we don't need content we need and sorting we don't need or can finally uh submit here and they have this input type submit instead of a button which is ridiculous but they have that still for some reason so i'm just going to leave it as the input type submit and there's this back to list action here and the validation scripts as we mentioned already okay looking good so save that and if i go to create new here here it is title and content and this is a text input and i want this to be text area so i'm gonna say text area here and get rid of name calls and rows and say asp for content like so and get rid of the input save that refresh okay great it's just missing a class so class of form control and asp visual studio that is and asp will it provide the bootstrap support which is really good so class form control let's see f5 to refresh and here's the text box so if i do control u here is the form or actually let me just right click and inspect it okay so here's the form action is slash admin slash pages slash create that's a method we still need to create but that's correct that's what we want method is a post and that's not valid here is because of jquery validation jquery validation is going to take care of the validation on the front end and form itself so you can see for example the title it has the id of title and name as well and here we just have asp4 sp-4 and the property which is title in this case so that's another tag helper there and is the same for the text area its id and the name are content which is the name of the property okay so and this data val and dataval and data were required that's for jquery validation so that's what that's for and so far this is looking good okay that's gonna be it for this video and we're gonna do the post request in the next video see you then in this video i'm gonna do the post create method so let's say here again in the create view sp action points to create okay and if i control you here again i can see that the form action is slash admin slash pages let's create and the method is post okay so i need to create that create method and this can be any method but it makes sense to have it called create because the get method is created as well anyway to create that method i'm gonna copy this details one and paste it here and i'm gonna change this comment to say post because this is supposed to handle the post request and slash create here like so and get rid of this end id and i'm gonna call it create okay so now i have two create methods but this create method is supposed to handle the post request so i'm gonna say here square brackets and http post like so so now this method is gonna handle post requests and if you don't specify the request attribute like we don't have it here or here or anywhere else in the controller it means it's get by default okay so here for example you can say square brackets and http get but you don't need to it's assumed that this is a get request if you don't specify anything else so in this way we can have two methods with the same name because they handle different requests okay so i'm just gonna get rid of everything in here and this as well so now i need to get that form data in here somehow so how am i gonna do that i'm gonna do it via model binding okay so model binding is a big deal in asp.net and it's a way to pass data to the methods or the actions so here this view uses the page model and these inputs here are properties of the page class so i'm gonna say here page page so i'm going to pass that page and the properties are going to be filled automatically with the values from the form okay so that's model binding and model binding tries to find values in models passed like so that's one way the other way it tries to get values is via a query string and the third way is via route parameters such as here for example okay so anyway i have this page here now which will have the values from the form so the first thing i'm gonna do is check if the model state is valid which means there are no validation errors so if model state is valid in that case it's all good and i can proceed okay so in here first of all i need to set the slug and i'm gonna turn the title into the slug so i'm gonna say page and slug and as you can see i have intellisense here and that's going to be equal to page title and to lower and replace spaces with dashes and shift enter to play the semicolon at the end and go to new line and i'm also going to set the sorting to 100 okay so each new page is going to have the sorting of 100 and i'm going to add the functionality to actually manage sorting via drag and drop later on but for now whenever a page is created it should go to the end basically be the last page when getting all the pages okay so the next thing to do is i need to check if the title or the slug exists so i'm going to say var slug and that's going to be equal to await context pages and first or default async where slug is equal to page slug okay so if slug isn't null then that's a problem and i'm gonna add an error to that model state so i'm going to say model state add model error and the first argument is the key which doesn't really matter so i'm just going to have it as an empty string and the message is going to be the title already exists okay and at this point i want to return because the title or the slug exists already so i'm gonna say return view and return that page information which is going to refill the properly filled out fields in the form and if that's not the case then it's all good so the model is valid and the slug doesn't exist or the title so i can add the page so i'm going to say context add and page shift enter and await context save changes async like so and also if the model state is not valid then again i'm gonna copy that return view page here okay but if it's all good and i added the page then i want to return a redirect so i'm gonna say here return redirect to action index okay and you can see now the benefit of this i action result it allows me to return both views and redirects for example in the same method which is really good okay great i'm going to end the video now and we're going to add the validation and test this out in the next video in this video i'm going to add validation to the page model okay so here in the page cs file there is already some validation here just required but let's add the minimum length as well and i'm gonna get rid of the required for the slug which i just had there for the migration if you remember so anyway i'm gonna save that and let's just test this out now okay it refreshed so if i click create i get here here i get that the title field is required and the content as well so that's great and if i start typing something it goes away the error message because it's valid now so that's great that's basic validation but i want to add the minimum length as well for the strings and you can have another validation rule here or this data annotation attribute as it's called so i can have that here say main length and so on but you can also have it in one on one line like so so i'm gonna have that required there and i'm gonna say comma and add another validation rule i'm gonna say min length and in parenthesis i'm gonna say two so that's the minimum comma and a custom error message i'm gonna say minimum length is 2 okay and i'm going to copy that line ctrl c and paste it here for the content and say that the minimum is let's say 4 for the content so minimum length is four i'll say here save that let's refresh and see okay so if i click create i get that the filter required and if i type one letter here now i get minimum length is two okay and another and now it's okay and here let's say b b b b and now it's okay because there's four characters so that works that's great let's try adding a page i'm gonna say test and test page here and create and i'm redirected to the index and here is the test page okay and let's try adding another page called test test page again and now i get that the title already exists which is coming from here this line right here okay so it's all good and as far as validation goes we're gonna get more into it later on but there's a bunch of these you can use minimum length maximum length regular expressions and so on and we're going to use some of them later on so just be aware that there's a bunch of these data notations you can use for validation okay that's gonna be it for this video see you in the next one in this video i'm gonna add support for flash messages so basically when i for example add a page i want to get the message here page added or something like that not just a redirect with the page being listed here but the notification as well and for that i'm going to use a partial view and before that here in the post create method i'm gonna use temp data to set the message and if you remember we saw let's see this view data as well and there's also temp data and view bag and i'm going to use stem data in this case because i'm doing a redirect here and if i use view bag it's not going to be available but with temp data it will be available okay so temp data is like view data it works with keys so i'm gonna say temp data and i'm gonna have a key here called success and that's gonna be equal to the page has been created or added let's say like so okay and then now to access this temp data success message i'm going to create a partial view and the partial view is like a regular view but it doesn't use a layout and you insert it into an existing view so i'm gonna have that in the shared folder i'm gonna right click and say add view and i'm gonna check here create as a partial view okay and the view name is gonna be underscore and notification partial so you don't need this partial at the end or the underscore but does the standard template is going to be empty and i'm going to click add okay here it is ctrl a to get rid of everything so in here now i want to check if that temp data success is active so i'm going to say at if for razer so if tem data success is not null in that case i'm gonna have a div with the class of alert and alert success and in here i'm gonna display the message so temp data success like so save that and i'm gonna inject so to speak this partial view in the main layout okay so in underscore layout here above the render body to include it i'm going to say partial and the name is notification partial okay and sp is going to look automatically in the shared view folder for that so this should work let's see if it does work so i'm going to go to create new let's say test2 and just some gibberish here whatever create and here it is the page has been added okay great and let me also show you a view back while we're here so i'm just gonna show you an example and get rid of it then let's say here in the index method so here i'm passing the pages list right which is the model but i can also pass arbitrary data using for example view bag or tem data as we just saw so to use view bag you don't use indexes but uh dot notation so i'm going to say here view bag and something let's say actually for example fruit and that's going to be equal to apples okay so now i'm going to have this viewback fruit available in the request which is index in the index view then so after this h1 i can say for example at and view bag and fruit save that and let's see if i refresh and here it is apples okay so those are ways of passing arbitrary data to views that don't have anything to do with the model so if you need to pass some extra information on top of the model you can use view bag or tem data for that and i'm gonna get rid of that now okay save that and that's gonna be it for this video see you in the next one in this video i'm to show you how to use csrf protection when posting forms and i also want to disable this delete link here for the home page so csrf stands for cross site request forgery and let me go to create new here to create a new page and if i go to control u to view the source let's see down here in the form there's this request verification token which is there automatically okay it has some value and to validate that token all you have to do in your post method is add the validate anti-forgery token attribute like so and that's gonna do it okay so you should do this when posting and once again the hidden input field here is always there automatically provided by asp okay and let's also disable the delete for the home page because the home page is never supposed to be deleted in this project so in the index view let's say here for the delete i'm going to say if item slug is not home then i'm gonna display the link otherwise i'm not okay so let's see what happens here refresh and good it's not there anymore so as far as the home page goes this home link that is it should never be deleted and the slug should always be home okay anyway that's gonna be it for this video see in the next one in this video i'm gonna add the edit page functionality so first of all i need to display the edit page view and for that i'm going to copy this details method and just copy it down here okay so this is going to say edit and some id and it's going to be called edit and i'm gonna need this id as well it's gonna be provided in the url as the route parameter so now we need to get the page page page and instead of first or defaultasync i'm just gonna say find async and paste the id so do it a bit differently this time so if it's now return not found otherwise return the view with the page okay so far so good now to create the view i'm gonna save this file and right click add view and view name is edit template is gonna be edit model class is gonna be page and make sure reference script libraries and use a layout pager checked and that created the partial view is not checked add okay here it is i'm going to change the title to edit page and here as well h1 get rid of the h4 and hr space this out a bit and this save i'm going to change to edit save that okay so the id i don't need like so title i needs like i don't content i do need and sorting i don't need because sorting is not going to be set this way and the content should be a text area so i'm just gonna go to create and copy from here copy that line and paste here get rid of the input okay so i have the title and the content but i need to pass also the id and sorting and i'm gonna use hidden input first for that so i'm gonna say input and colon hidden and i'm using that zen coding extension for vs for visual studio that's why i have this shortcut anyway input type hidden and i'm gonna say asp4 and id and control d and this one is going to be sorting okay that looks good there's this back to last link here which is fine pointing to index action and the validation scripts so that's all good the only thing we're missing is the post method to handle this form submission so for that back in the pages controller i'm gonna copy this create post since it's kind of the same thing so copy that and paste it here so this is gonna be post admin pages edit and it's going to be called edit and i'm going to pass the page here so that's good okay so first of all i want to check if the model state is valid and next i want to check if the home page is being edited because if it is i don't want to added a slug this lock for the home page should always be home so you can change the title and you can change the content but not the slug okay so let's just check here in the index view if i go to edit or details here if i hover over it i can see in the bottom left that the id is one so that's what i'll use for to check if it's the home page so i'm going to say page slug is gonna be equal to if page id is one slug is gonna be equal to home otherwise it's gonna be this so just copy and paste that there and now i don't need this line or the sorting because i'm passing the sorting through the hidden input field now again i want to check if this log exists but not for this particular page right i want to check if it exists for some other page any other page but not this particular one so i'm going to modify this a bit and add a where in here so i'm gonna say where xxid so where the id is not equal to page id okay so now check if this log is not null if it's not that's a problem so the title already exists actually i'm going to say the page already exists that kind of makes more sense and here as well the page already exists okay return view page that's fine in case it does exist otherwise instead of add here i'm gonna say update so context update page and save changes async and temp data success the page has been edited okay and i'm going to redirect to action and the action is edit but let's see here the get request it needs this id as well so i need to pass that as well here so i'm going to say here new and id is going to be equal to page id save that okay looking good let's see now if i go to edit let's say about this here it is so i'm going to say about us 22 here and two to two for the content as well add it and the page has been edited i get and i'm back at the page and i can see the updated values and if i go back to list it says about us 222 here and the slug is changed as well and if i go to details i can see the content as well okay so that's all good and let's try to for example call this title services and edit and the page already exists so that's not gonna work which is great okay that's gonna be it for this video see you in the next one in this video i'm gonna add the delete page functionality so let's see here in this index view if i hover over delete i can see it points to the delete method so i'm gonna create that method now and for that method i'm gonna get this edit method copy that and paste it down here so this is gonna be slash delete sum id and get request and i'm gonna call it delete and i still need this id in here so that's good okay so first of all i'm gonna try to find it then check if it's now if it's now then i'm gonna get this stem data and have a temp data error here and i'm gonna say the page does not exist like so otherwise i'm going to have an else here let me just pay this out a bit else it does exist so i'm gonna remove it so i'm gonna say context pages and remove page and await context save changes async okay and i'm going to have this stem data let me just copy from here actually the success one time data success and the page has been removed or deleted let's say and i'm gonna return a redirect to action index the name of the action save that okay so i need to create this uh tem data error message in notification partial so i'm gonna highlight ctrl d to copy and this is gonna say error so if error is not null this is gonna be alert alert danger and then data error and also now when we display this message it stays there forever until you refer the page or go somewhere else and i want it to disappear after a couple of seconds so i'm gonna add another class here notification and here as well okay save that and also when i click delete here i want to confirm that i want to delete the page i don't want it to just get deleted so for that in the index view pages index i'm gonna give a class to each delete link so class confirm deletion save that and i'm gonna have it confirmed by javascript so for that i'm gonna go to www root and jis and site.js and this site.js comes with the mvc template so in here i'm gonna check for that confirm deletion and let me just go to the layout and here it is okay being included so anyway in here i'm gonna have that jquery ready so dollar sign and function semicolon there okay so in here i'm going to say if a confirm deletion length so if it exists then i'm gonna say a confirm deletion on click and have an arrow function in here and here i'm gonna say if not confirm confirm deletion return false save that okay so they should hopefully work refresh and if i click delete for test for example i get the page has been deleted so there's no confirmation so let's see what's up with that let me refresh the page again and check and there's definitely no confirmation so i guess i messed up the class confirm deletion okay copy that and oh yeah i messed up the class name here okay anyway save that and before we check that let's add some javascript here to have that notification thingy go away so i gave you this notification class here so i'm going to use that and let me just copy this whole thing copy paste so if div class alert class notification length so if it exists and get rid of this i'm gonna say set timeout and have an arrow function in here and let me just copy this so develop notification and fade out like so and that should happen after two seconds okay so let's check everything again refresh and i'm gonna go to create new because i don't want to delete any page i have now test test create the page has been added and it goes away after two seconds great and now to delete it delete confirm deletion cancel nothing happens delete okay and it's deleted okay great it's all good that's gonna be it for this video see you in the next one in this video i'm going to show you how to get client-side libraries in asp and we're also going to turn the text areas into wizardwicks and before all that let me just go to the edit page and i want to change the column here it's not wide enough so i'm just going to go to edit and change this column d4 to 10 same as create i believe yes okay let's just refresh and see okay looking good so the way to get client-side libraries in asp is to use libman and if you've never used libman you'll see it's pretty good so i'm gonna right click the project and go to add and client-side library and now i'm gonna get this provider list okay so there are these four and this is libman in action so you can see the target location is www root slash lib which is correct since that's where jquery bootstrap and so on is so anyway here you can search for whatever you want i'm gonna search for ck editor and here it is this version is fine and i'm gonna click install you can see down here that something is happening okay it finished after a while so now in lib there's uh ck editor okay so that's pretty good and also there's this libman.json file now that's been created so that's the way to get client-side libraries that's basically built in the built-in way but of course you can use mpm for example if you want but you would have to write a script for the task runner such as gulp or whatever to actually move those packages into the lib folder and so on so if you can get it with libman that would be advisable since it's the easiest way okay so anyway i have this cke editor now and to use it i'm gonna open the layout in admin and the drag seek editor.js down here above site.js okay to include it save that and in edit cshtml down here in scripts in section scripts that is i'm going to have a set of script tags for javascript and i'm going to say ck editor and replace and name or the id of the element of the text area so content okay let's see if that actually works refresh and here it is great so this is a wysiwyg you can here for example headings here lists and so on so the html stuff basically okay so great that works let me just copy this and paste it in create as well so we have it there as well save that let me just indent that a bit like so and here as well so if i go back to list now and create new and here it is it's working okay great so let me go into each page and just edit so that actual html gets saved instead of just plain text so i'm just gonna edit h1 and contact okay so now if i go to details let's say for about this and let me actually change this about us to remove the total tool like so and here as well edit okay so if i go to details for about us let's say you can see here i can see the p tag so it's actual text and to display that as html i'm gonna go to details view and for the content i'm gonna say html and raw okay and pass content here model content that should be actually save that and let's see now okay now it should be an actual p here so if right click and inspect here it is it's in p tags so great okay that's gonna be it for this video see in the next one in this video i'm gonna add the sorting functionality for the pages so to do that i'm gonna be using jquery ui's sortable so let's see now here in the lib folder i don't have a jquery ui so i need to get it okay so to get it i'm gonna go to right i'm gonna right click that as the project and add client-side library and i'm gonna search here for jquery ui here it is okay this version is fine installed okay seems to have finished here is the ui folder so now i'm gonna go to layout and include this jquery ui script so i'm just gonna drag it and drop it after jquery script like so save that okay so that's the first part done next i'm gonna go to the index view so here okay and i need to make some modifications to the table okay so first of all i'm gonna give it a class of sorting as well so table sorting and i'm gonna give it an id of pages and to this tr here i'm going to give a class of home and to htr in the loop i'm gonna give an id of id underscore and item id so the id of the page and this is how you have to do it for the sortable functionality that's what it expects and i'm also going to give it a class which is going to be the slug of the page so item slug and i'm giving it a class of slug here whatever the slug is because i don't want the home page to be sortable okay and that's why i gave this tr here a class of home so home always has to be the first page or the first menu item and all the other pages can be sortable okay so that's that for the table and now down here i need to have some jquery so let me just go to let's say edit and just copy this whole thing because of section scripts and get rid of the sick editor okay so in the script text here i'm gonna get that table so table id pages and t body and you need to get the t body when you use sortable with the table and say sortable and pass an object and in here i'm gonna say items so which items are sortable and i'm going to say tr column not and dot home so all trs except the ones with the class of home okay and the placeholder class which i'm going to call ue their state dash highlight like so and you're going to see what that does in a minute and finally the update so this subject is going to be a function and here now first of all i need to get all the ids so i'm gonna say let ids and let me just copy this pages tea body and i'm gonna say sortable and serializing here okay so i'm gonna serialize all the ids which means i'm gonna turn them into a string a string representation and i can specify the url as well in a variable the url is gonna be slash admin slash pages slash reorder okay and now i'm gonna make an ajax post request so post url and pass the ids and i'm just gonna have an empty callback here save that okay so hopefully that should do it for the index view and i don't have the reorder method this one written yet in the controller but we can still uh test this out see what happens when the request is made okay so inspect and now if i click any tr you can see i can drag it and let me add some css to make this a bit nicer and easier to see so i'm going to press ctrl comma and go to site css and after all this stuff here i'm just gonna have a comment like so for my own stuff and i did the ctrl k ctrl c there to make a comment okay so in here i'm going to say table with the class of sorting and tr but not home so those trs that don't have a class of home for them i'm gonna have cursor pointer and that ui state highlight is gonna be the border basically around the place where the item is supposed to be dropped so for that i'm going to say border one pixel and dashed and ccc okay so let's see that now i refreshed and if you don't see any changes in home then do a hard refresh ctrl shift r to clear the cache and now you can see that the cursor changes to pointer for all the tr's except the home tiers okay and if i drag you can see that there's border where i'm supposed to place the tr that i'm dragging and let me go to network here so let me get this contact and just drop it here and here is the request obviously it's not going to work because there's no reorder method but let's see what it sends so down here you can see the form data and if i go to source it's the id's serialized so it's basically an array of ids okay so that's what i'm gonna use in the reorder method okay so let's do that in the next video in this video i'm going to continue with sorting or reordering of the pages and this is where i stopped the previous video so as we saw at the end of the video this is what's passed the serialized ids which is basically an array of ids so i'm gonna use that in the method and for the method i'm gonna go to the pages controller and let me just copy this post create method and paste it here so this is gonna be admin pages reorder post i don't need this anti-forgery validation and i'm going to call it reorder and as we said we're passing that array of ids so in here i'm going to say enter a and id okay so this right here and i'm gonna get rid of everything here in the body of the method and i'm gonna initialize a variable here called count so count is going to be equal to one and this is going to be equal to one because the first sorting number will be one because home is zero so home is always first and the others are going to go from one upwards okay so discount is one to begin with and i'm gonna save for each so for each var page id in id i'm gonna say page page and await context pages where x x id so where id is equal to page id and actually let me simplify this and just say find async so find async id a page id that is and for that page i'm going to set the sorting to count and say context update pass the page in here and await context save changes async okay and finally i'm gonna say count plus plus to increment the column by one for each iteration and finally i'm going to return ok so let's see what this ok is if i hover over it i can see that it returns status 200 okay so as you can see you can return even this with i action result okay looking good so save that and let's refresh here okay here it is so this is the order right now and if i say i want contact to come first when i say first i'm in the first after home okay i get status 200 okay so it's good and if i refresh i can see that contact is the first after home and if i go to the table so let's see and tables so right click pages and view data you can see here that contact here sorting of one about us two and services three so if i say i want services to come after contact okay i get an okay here so the request was okay and if i refresh here now services is two and about as is three and if i refresh i get it in the order that i just made okay so great working good that's gonna be it for this video see in the next one in this video i'm gonna create the categories controller model and migration so i'm gonna right click controllers go to add controller empty and call it categories okay here it is and let me just open up pages as well so i can just copy this cms context dependency injection so just paste that there and change the constructor name and import and let's just copy this area admin here above the class and okay looking good that's it for the controller so far let's now create the model so right click models add class and i'm gonna call the class category okay so here i'm gonna have i'm gonna say prop double tab and id then i'm gonna have a string name and string slug and end sorting so we're gonna have sorting for the categories as well and i'm gonna add some validation here now so for the name i'm gonna say mean length and required and let me actually just copy from page for that so this one right here so paste that there and import data annotations okay so this is good and i'm gonna say required for this log as well just so it's not null in the table so the column is not null when we do the migration like before and let's add another validation to name just to spice it up a bit and show you something new so i said before if you remember there are loads of these validation attribute you can use it really depends on your needs so when you need something just look it up but let's add another now let's add the regular expression so i'm going to say irregular expression and in parentheses i'm going to have a simple rejects so i'm going to have a sign here and double quotes and the pattern is going to be simple let's say we want to allow dust letters okay so of course you can have any pattern you want but i'm not going to go crazy with this i just want to show you how to use regex invalidation so i'm going to say carrot here oops here it is for the beginning of the string and in square brackets i'm going to say a to z and a to z uppercase plus and a dollar sign for the end okay so this pattern means that only letters are accepted and i'm also going to have an error message here actually inside of the parenthesis so anyway error message and that's gonna say only letters are allowed okay looking good save that and now let's create the migration so i'm going to open package manager console and actually before that we need to add the model to the context so let's actually do that right now so cms shopify context and right here we need to add that db set which is going to be category type and i'm going to call it categories save that and now we can do the migration so i'm gonna say add dash migration and i'm gonna call it second create okay so let's check the migration folder here it is and you can see we have this second create file now with the timestamp and here's the up method which creates the tables and here's the new categories table so let's uh say now update dash database okay let's open the database in c if it's all good so local db databases cms shopping cart and the tables and here are the categories so let me just view data in pages to see it's all there still it's all good and the categories i'm gonna go to right click and view designer okay so id name slug sorting all are not null and that's it looking good to me okay that's gonna be it for this video see in the next one in this video i'm gonna do the categories index method okay so here it is it got created when we created the controller but let's make this async so i'm going to say async and task i action result and now we need to get all the categories so i'm gonna do this a bit differently then i did it here in pairs controller here we had this syntax and now i'm gonna do something else i'm going to return the view and get the categories in here so i'm going to say await context categories and order by sorting and to list async okay and i need to import this ef core okay great save that and create the view so right click and add view index template is going to be list model category reference script libraries user layout page add okay so for some reason this is saying the model doesn't exist in the current context and so on but we have the categories folder created and the index so let me just go to admin categories and see if it works and it does is just that visual studio was bugging out a bit okay so anyway here it is and i'm gonna just get rid of this cms shopping cart models namespace and let's say here i don't want the id or the sorting and i'm going to say here categories and here as well for the h1 and i'm going to get rid of the slug too actually i don't really need that so just the name and in the loop get rid of the id td and slug insorting okay save that and i'm gonna change these actual links to use anchor helper tags tag helpers that is same as for the pages so in pages index down here i'm gonna copy these a's and get rid of these links here and paste that just get rid of this if there and this lack of syntax highlighting is really annoying i don't know what's happening it's tripping up a bit so let me actually just exit the iis and i'm gonna close the solution and reopen it so let's say close solution and reopen it okay now it's normal finally so anyway let's see here item id added details and the details i don't really need since it's just the category name so i'm just gonna have edit and delete okay looking good save that and let's see what else we can change i don't think there's anything else to change so let's ctrl f5 to run without debugging okay so here it is slash admin slash categories okay looking good i'm just gonna add the menu item to the layout so layout and copy this link ctrl d bring it down so controller is gonna be categories and this is gonna say categories as well save that and refresh okay here it is so pages categories okay great and let me just add the hover effect for the ace just so we know we're hovering over some links so control comma and go to site css and down here i'm just going to say a hover and opacity 0.3 and just make it important okay so ctrl shift r to refresh with cash cleared and okay this is easier now to spot that we're actually hovering over something okay great that's going to be it for this video see in the next one in this video i'm going to add create category functionality so once again i'm going to open pages controller and just copy some call from there this get create so this is good i'm just going to change pages to categories here in the comment and add a comment here for the index as well so get admin slash categories okay now to create the view right click and add view so create template is create as well model class category add and here it is i'm going to change this to this h1 to create category and the title as well create category get rid of this namespace here i'm going to change this column d4 to 10 like so okay so let's see here i don't need the id name i need and slug inserting i don't need okay so back to list and validation scripts seems good let's see i'm gonna go to categories and create new and here it is looking good so if i click create the name fill is required and if i enter a number you can see i get only letters are allowed so that's let's just find it this validation here the regex okay and while i'm here i'm gonna get rid of this required for the slug as well i don't need that for the form validation and if i end if i enter a letter i get minimum length is two and two letters and it's all good okay so that looks good but we need to create the post method as well to handle that so i'm gonna do that now down here and again i'm gonna copy from pages so copy that post method this is going to be post admin categories create and this is going to be category okay so first of all check that the model state is valid next get the slug and set sorting as well so this is going to be category name let's see for some reason i don't get intelligence oh because this isn't imported okay import category and now i get intelligence okay so slug and sorting and the next i want to check if the slug exists because i don't want to have two categories with the same name so context and categories here first or default where slug is equal to category slug and change this to category already exists and return view category in case it does exist and context add category here save changes async then data success the category has been added redirect to action index that's fine and finally return view with category in case there are model errors save that okay let's see now if we go to create new and add a category let's say fruits okay the category has been added it disappears and here is the category name here fruit so addy doesn't exist but it works and delete as well and create new and the t-shirts i'll call this one and it says only letters are allowed and that's because of this dash here so let me just change that validation a bit we have a dash in here as well okay refresh t-shirts let's see and create and okay here it is and let me actually add the slug for the index as well just to make sure it's all good so in the categories index i am gonna have slugs so highlight and copy that and let me actually while i'm here get rid of this since i don't need all that code so just name and slug and ctrl d to copy that td and this as well i'm just gonna say item and name and item slug i don't need that display for save that and let's see again okay great let's also add the test category like so add that and let's try to add another category called test and the category already exists okay so that works fine as well so far so good that's gonna be it for this video see you in the next one in this video i'm gonna add the edit category functionality so once again i'm gonna copy from pages so get this method here and change it the comment that is to categories edit and sum id and this is going to be category and category await context categories find async id and if category is now return not found otherwise return the view with the category okay good let's create the view right click and add view so view name edit template is going to be edit mode class category okay so here i'm going to get rid of this id and get rid of the slug and get rid of the sorting as well and get rid of this h4 and hr and this is going to say edit category and edit category here as well and get rid of this namespace but i do want to pass the sorting in here and let me actually just change this to edit as well the submit button so i'm gonna have a hidden input here input hidden and i'm gonna say asp4 sorting okay and if you remember for the pages i passed the id let's see edit pages i passed the id here and in the edit post here i got the id via the page model okay and i'm gonna do it a bit differently in this one i'm not gonna let me close this one so this is added category i'm not going to pass the id here because let's have a look if i go to edit and let me edit this test and here it is so if i right click here and inspect you can see that the form points to slash edit slash the id so it has the id so i can get it from there as well okay and i'm gonna do that now just for variety sake in the post method so let me still copy the post edit from page because it's going to be similar regardless paste that there so this is categories edit and slash sum id so i'm going to say here end id and then pass the page okay and let's see here what we need to change and by the way i just want to mention because some people complained for some of my courses uh for this copy pasting but i'm copy pasting these methods because they are nearly identical and that's what you do in real life okay so you're not supposed to write every single character or letter if you don't have to you're supposed to understand the code so you need to study the code and understand what's happening in each line that's the point and i'm copy pasting methods if they are similar to not waste time and show you how it's done in real life okay so there's no point for example here to write all of this again is just literally a waste of time so hopefully you don't mind that i'm copy pasting and editing so anyway back to this post method i don't need to check if the slug is home so i just need a slug so i'm going to say this is supposed to be actually category so i'm going to say category slug is gonna be equal to the name which is modified a bit like so okay now check if it exists so context categories here where id is equal to and i'm not gonna do category id here like so i'm just gonna pass the id from the route parameter so this one right here first or default where x log is equal to category slug okay so check for that if it's not null it exists so i'm gonna say the category already exists and return the view with the category here and let me just check here that i have the correct message i do okay anyway them data success actually here page change to category so update category save changes async temp data success the category has been edited and return redirection redirect to action that is edit and id equal to id or since the names here are the same i can just do this it should work and return view category here and save that and let's see if that works so i'm just gonna go back to list just in case okay so edit test and test tool for example edit actually that's not gonna work so test test edit okay the category has been edited and i'm back here so it's all good i'm back where i should be if i go back to list i can say that the name and the slugger changed and if i let's say go to edit and try fruits the category already exists so that's not gonna work which is great okay so far so good that's gonna be it for this video see you in the next one in this video i'm gonna add the delete category functionality so once again i'm gonna copy from pages and this delete the method so copy that whole thing ctrl c paste it here ctrl v so get admin categories delete and some id okay so this is supposed to be a category and category and categories here copy that so if category is now the category does not exist does the error otherwise context categories remove category save changes success the category has been deleted redirect to action index okay looking good let's test this out refresh the page so if i go to delete test i get confirmed deletion if i click cancel nothing happens and i get that because in the index there's this confirm deletion class for da right which we had for pages as well because i copy pasted these a's from the pages index these anchors so anyway i'm gonna delete again and okay and the category has been deleted and it's removed from here so it really is deleted and by the way let's see this um error in action so that's if the category is null so i'm gonna manually go to to a link here to delete the category so slash delete slash and 333 for example so something i know doesn't exist and now i get the category does not exist i mean there's no reason for the admin to do that but i just wanted to show you what happens in case it doesn't exist and some people make this delete method a post okay which is what the scaffolding does in sp when you scaffold the crowd operations and i'm gonna show you that in the standalone lessons but i personally usually have it as a get request okay but anyway that's up to you but for this project the deletes are gonna be get requests so anyway the delete works and the only thing left for the categories right now is the sortable functionality and we're gonna do that in the next video see you then in this video i'm going to add the sorting functionality for the categories so right now if you go to the categories table and view data the sorting is 100 which is the default okay so first of all i'm going to go into the index view since i need to make some modifications here so here i'm going to give this table a class of sorting so it has those css classes and i'm also going to give it an id of categories and to these trs i'm going to give the id of id underscore and the id so item id which is needed for sortable to work and i don't need to give it those classes because i want all the categories to be sortable okay so that's it for the table and let me go to pages index and get this jquery section scripts okay paste that here and let me just change this pages to categories and copy that and here as well and here as well okay that should do it for the index view now i need to create the reorder method here in categories controller and for that i'm gonna copy from pages so this one right here paste it here so this is gonna say categories and this is gonna say category and category and this i'm gonna call category id copy that this is category id and this should be categories and category here and here save that looking good no reds quickly so let's control shift r here for a hard refresh okay and i get that cursor pointer let me inspect just to refresh again just to see if it's all good so i'm gonna say t-shirts come before fruits and i get the status 200 okay here and if i refresh t-shirts are indeed before fruits and if i say fruits are before t-shirts and refresh it stay so okay looking good let me just go to the table and here it is sorting is one and two and if i say t-shirts are first and refresh here now sorting is two and one okay great that's gonna be it for this video see in the next one in this video i'm going to create the products controller model and migration so i'm going to right click controllers in the admin area go to controller and call this controller products controller okay and i'm just gonna open pages and get the context the database context just so i don't need to type it out and change the constructor name import cml shopping cart context and get this area admin attribute for the class okay great that's gonna do it for the controller for now let's now create the model so in the models folder right click and add class call it product and here i'm gonna have an end id shift enter to go to the next line and i need the name product name and let me actually ctrl d here to copy the line and the slug ctrl d again and this is gonna be description and i'm gonna have a decimal price and i also need to have that category id because each product is gonna belong to some category i also need a string for the image product image okay so those are the fields i need for the table and the model but i also want to specify that this category id is a foreign key right this is a foreign key to the primary key in the categories table so to do that i'm gonna create a virtual field here of type category and i'm gonna call it category and i'm gonna annotate it with foreign key and import schema and specify which field is the foreign key so that's category id okay so this is going to make the connection i also want to add some validation here so i'm going to open the page and get this required eminem length and i'm gonna have that for the name for the let me import this actually and for the slug i'm not gonna have anything so i'm just going to have it like so but the description as well needs to have some validation so required minimum length can be four let's say and error message manual length is four and for the price i'm gonna specify that it's a decimal type for the table so i'm gonna say column and type name and that's going to be decimal and 18 comma 2 in parenthesis okay and the rest is fine for now so save that and now let's create the migration so package manager console and i'm gonna say here add migration and the third create okay now i'm gonna say update dash database actually i forgot to add the product to the context so let me make a copy here and say product and products here okay and i'm gonna get rid of this third migration here so let me just add migration again and now update database okay so let's see now right click right click and refresh and here it is so i'm gonna right click and go to view designer okay so notice that it has a foreign key okay so category id is a foreign key and it says so here as well so foreign key category id references categories id and it's gonna cascade on delete which means that when you delete a category all the associated products will be deleted as well okay and we'll see how all that works in a bit so anyway so far so good that's gonna be it for this video see in the next one in this video i'm going to create this index method for products controller so i'm going to go to categories controller and just copy from here and get rid of this one here that's created so this is gonna say admin products and it's gonna get from products and there's no order by actually there is but by id but this is going to be descending and to list async and include ef core import it okay and i'm gonna modify this method more because it's gonna use pagination but for now i'm just gonna have it like this but one more thing i want to add in here is i'm going to say include and include the category that the product is connected to so i'm going to say xx category and now let's create the view so right click add view index and template is going to be a list and model class is gonna be product add that okay so here i'm gonna save products for the title and get rid of the namespace and products here as well and save that so let's see now the id i don't need i need the name so i'll get rid of the id and i need the name and slug and description i'm not going to have in this list price i will category id i will and the image i'll have as well and let me just get rid of this c sharp code here so name price and this is going to be the category actually another category idea so i'm going to get the category name automatically via this include here okay so this is gonna be the image okay get rid of the id here and this login description so name price category and image and let me simplify this so here i'm going to say item name and item price and for the category id i'm not gonna say item category id i'm gonna say item category and the name so to get the name of the category okay so that's that foreign key connection and the image is gonna come later on so for now i'm just gonna say image here and for these a's here these action links i'm gonna replace them as usual with tag helpers so copy from index pages or categories wherever get rid of this if okay so edit details and delete looking good so let's refresh this now okay and let me actually add the products link to the layout here so ctrl d and this is gonna be products and here as well so let's refresh again okay here it is if i click it i go to products so great so far so good that's gonna be it for this video see the next one in this video i'm gonna add get create method and view so to get started i'm gonna go to pages controller and just get that create get create from here so this one copy that and paste it here so this is going to say products and i'm going to have curly braces here okay so here i want to return the view but i also want to pass the categories to this view so that when i'm creating a product i can choose a category for the product and you can have this for example as a list like a list of categories and then pass it to the view and loop through it there in a select list and so on you can do that but isp supports creating actual slight lists and i'll show you what i mean now which is a much better way so anyway to do that i'm gonna say here view bag and category id i'll call the property and i'm gonna say new select list okay and i need to import from mvc rendering and let's say control space here ctrl shift space that is there are five overloads and i'm gonna use the third one so i need the items and actually the third one i'll use so i need the items and the data value field so the option value and the option text okay so i'm gonna say here context categories and order by so order by sorting okay and i'm also going to say here id and name like so name like so so these are the properties of the product model and this idea is going to be the option value and name is going to be the option text okay so this is a really great feature and to create the view now right click add view create template create model class product and add okay so here it is let's just clean this up a bit get rid of the namespace and the title is going to be create product copy that create product here as well get rid of this h4 hr okay so in here let's see let me just pay this out a bit i don't need this id and the name i don't need slug i don't need description i need and price i need as well and category i need and the image okay so this description should be a text area so let me just copy from pages create copy this text area and paste it here get rid of the input and change asp4 to description okay so name description price and now this category so instead of input i'm gonna have that select so i'm gonna say select here and asp4 is gonna be category id and i'm also gonna say asp items okay to get those items and this is going to be view bug and category id and i'm also going to give it a class of form control like so and in here i'm going to have one option with the value of zero which is going to say choose a category save that and let's see what this looks like so create new okay here it is looking good i just need to turn this into call md10 okay so here's the categories and if directly can inspect you can see that the issues has a value of 2 which is its id and fruits 1 which is its id so that's great i just want this to say category not category id so you can just say category here save that and let's see that works of course but for variety sake i'm going to get rid of that category and that's the way i would usually do it but because this is a course i'm gonna go to the product model and if you remember from before i talked about that display name so i'm gonna use that here now i'm gonna say display and name is gonna be equal to category so now this sp4 here is gonna kick in otherwise you don't really need it for a label but in this case we're gonna use it like that to change the name the text of the label that is okay so here it is category again great okay so that's all good and i need to turn this description into a wizardwick so let me do that as well i'm gonna go to pages create and just actually get this whole thing let me see actually what i already have that so i'm just gonna get script and ck editor okay and then this a bit and this is gonna say description save that and refresh okay great and finally this image so for the property in the product model i have a string image but actually i want to upload an image file here so i'm gonna change that here okay so instead of this image i'm gonna say first of all product image here now it says adjust image so just to spice it up a bit and for the input here i'm not gonna have this image which is a string right here okay i'm going to create a new property here so prop double tab and the type is going to be iform file so forum file and import this from http and i'm going to call it image upload okay and i don't want this image upload property to have anything to do with the table so i'm gonna say here not mapped okay so this is one way to do it another way would be to create another product class which would serve just as a view model which would have this property as well but instead of creating two classes that are basically the same i'm just going to have one class which is going to serve both as a dto or a data transfer object so it represents the table in the database and it also serves as a view model which is the data that the view expects okay so anyway once again because of this not mapped here this image upload property isn't going to have anything to do with the actual table in the database okay so now back in here instead of input sb4 image i'm going to say sp4 image upload and the validation for image upload as well but i still need to add validation for that but anyway i'm just going to have this sp validation for here for now okay looking good let me refresh here and see what happens so here it is now the product image is a file type okay so that's great and finally i need to tell this form to support image uploads or file upload so here in the form tag i'm going to say anc type and multi-part form data like so okay great that's going to be it for this video see in the next one in this video i'm gonna add image preview functionality so when i choose an image here i want to be able to preview it here okay so in the create file below this image upload input i'm going to create a placeholder image so omg and source can be empty and id is going to be image upload save that and for the functionality i'm gonna add the javascript function to the site.js so i can reuse it elsewhere okay so control comma and i'm gonna go to site.js and here i'm gonna create that function outside of this jquery ready because of scope so i'm gonna say function and i'm gonna call it read url and pass input in here okay so first i want to check that there is a file so i'm gonna say if input files and input files first in that case i'm going to create a new file reader so i'm going to say let reader equal to new file reader and reader on load is going to be equal to a function and i need to pass the event for the function so e in here and a semicolon there so get that image preview and set the source so attr and source and the source is going to be it target and let me just get rid of this pop-up result and i'm also going to set it width and height here so i'm just going to say width 200 and high 200 as well okay and finally i'm gonna say reader and read as data url and pass that file so input files first okay that should do it for the javascript function and now here in the create view i want to respond on the change event for this file input so here i'm gonna get that input which has the id of image preview and say change and pass a function in here and i'm going to call that function so read url and this save that let's see if this works refresh here okay so choose file and i'm inside the course files which you can download in the last lecture for this course and let's say i'm gonna choose apples and nothing happens for some reason let's see why oh this is supposed to be image upload not image preview okay so image upload save that and let's refresh again choose file apples and still nothing happens let's see what's up there are no errors maybe i messed up the id let's see what it says here oh it says image preview here yes so i'm just going to copy that and paste it here sorry about that hopefully now finally it's gonna work choose file apples and here it is okay great that's gonna be it for this video see you in the next one in this video i'm gonna add validation for the category so if i click create now you can see that i don't get any error for the category even though i don't want this choose a category to be an option and if i right click and inspect and let's see here so that option has a value of zero so i'm gonna use that to do the validation okay so in the product model here actually here i'm gonna do something new i'm gonna add a range okay so i'm gonna say range and i need minimum maximum here so i'm gonna say that minimum is one and maximum is and max value and an error message which is going to say you must choose a category okay save that refresh and let's see now if i click create and i get here you must choose a category and if i choose some category it goes away okay great that's gonna be it for this video see in the next one in this video i'm gonna add custom validation for the image okay so there is actually a file extensions validation attribute so you can do something like file extensions and then set the extensions here and so on but this doesn't really work for file types it works only for strings basically okay so it doesn't really make sense but that's how it is so it wouldn't work for this image upload or file upload whatever the file is and this is gonna give us a chance to create our own custom validation which is really handy okay so i'm gonna get rid of this file extensions so this file extensions plural is the built-in one and my one is gonna be called file extension okay so for now i'll just get rid of this and to create that custom validation attribute i'm gonna go to infrastructure and i can go anywhere i can create this class anywhere but i'm gonna do it in here and go to add class and i'm gonna call it file extension attribute okay so the name should be whatever you want to call it plus the attribute suffix so add and here it is and this should extend validation attribute okay so there's data notation here imported so in here now you're supposed to override a method of validation attribute called is valid so let's do that i'm gonna say protected override and validation result is the return type and is valid here it is okay so i'm passing here object value and validation context and i'm going to get rid of the return so the value is the value that's passed for evaluation and validation context can be used to get services if you need to okay so we don't need the database context service or dependency in this case but i'm going to show you how you would get it if you did need it so if you wanted that database context you would do something like var context and that would be equal to cash to cms shopping cart context and say validation context and get service and have a type of in here so type of cms shopping cart context okay so now if i do context dot mp let's say so here the pages if i do what else we have categories so see here the categories and p for products pr products okay so you have that contest available now but as i said i don't need this context for the file upload validation so i'm just gonna leave this here and i'm gonna just make it into a comment so control kc and leave it here for your reference okay so anyway back to the file upload validation so let's say you wanted to validate a string you would use this value you would call it's a tostring method that is so valid and to string a value that is not valid value to string okay so you would use it like that if you wanted to validate a string but i want to edit the file so i'm going to save our file and value as i form file okay and i got automatic import so make sure you have that as well so now i'm going to check if the file is now or not null actually so if file is not now so first of all i want to get the extension and i want to validate let's say for jpg or png only okay so get the extension which is gonna be path and get extension file file name and i'm getting this automatic import so when i wrote path i got to using system io here so just make sure you have the correct using statements here for everything okay so anyway that's the extension and i'm gonna make an array of allowed extensions so string array extensions and as i said so jpg and png let's say and now i want to check if the extension variable contains extensions so i'm going to say bool result and extensions any and x extension ends with x okay so if not result if the result is false which means that the file doesn't end with jpg or png in that case i'm going to return new validation result and i'm going to have a custom method here called get error message okay and that method doesn't exist so let me just generate it and this is going to return a string and i'm going to say here return and allowed extensions are jpg and png okay and back in here so if the file is a jpg or png i'm going to return validation result success okay so that should do it for the validation actually this return is supposed to be outside of the if okay and let's see looking good i'm just gonna build the project to make sure there are no errors so it's f6 for me might be a different shortcut for you okay it's all good and finally i'm going to add that validation here so file extension okay and if i control click it i go here so once again the attribute name should be whatever name you want and this attribute suffix which isn't going to be used when applying it such as here okay so it's just file extension okay great looking good but i'm not going to be able to test this out here now because i need to create the post method to handle the request because as it is now the validation is only going to kick in after the request okay it's not gonna be using jquery validation to check for it here okay so anyway that's gonna be it for this video see in the next one in this video i'm gonna add the post create product method so here i am in the product controller and i'm gonna go to let's say pages controller get the post create from there so this one right here copy that and paste it here okay so this is gonna say products create and this is going to be product so let's say check if molestate is valid okay set the slug so product slug and import models so product slug is going to be equal to product and name okay to lower and replace spaces with dashes get rid of this sorting check if slug exists so check if the product name already exists so context products where slug is equal to product slug if it's not null we're going to say the product already exists exists and return view with the product and then i'm gonna say context add product await context save changes async and temp data success the product has been added and finally return a redirect to index okay so this is the same stuff as we had before but in here now i need to upload the image as well so that's going to be new so first of all i'm going to add another dependency to this class to this controller so up here i'm going to say private read only and this is going to be i a web host environment okay and i'm going to call it web hosting environment and that comes from this sp dot sp net core hosting okay so make sure you have the correct using statements there correct imports i got that auto imported okay so anyway back to this post create so in here and this is actually supposed to return product okay so in here we need to upload the image so first of all i'm going to say string image name and have this variable here that's going to be equal to no image.png okay so this image is going to be the default image in case no image is uploaded and for that and the uploading of the images in general i'm gonna create a new folder inside of www root so right click add folder and i'm going to call it media and inside of that folder i'm going to create a new folder and call it products so this folder products is going to contain the product images okay and i'm also going to get from the course files which you can download in the last lecture of this course the no image png image and let me drag it to products okay so that's there as a default and now let's handle the uploading of the image and by the way i just realized i didn't mention let's see what this web host environment does when you hover over it it says it provides information about the web hosting environment the application is running in okay so we're gonna use this to get the paths we need anyway down here again first of all i'm going to check if anything is uploaded so if product image upload is not null so in that case first of all i'm gonna set an upload there and for that i'm gonna say path combine using system io for the path and the web hosting environment web root path and i want to combine the web root path with media products so the second argument is going to be media slash products okay so this is going to combine whatever the root path is slash media slash products to get the correct path to the uploads there and now i'm gonna modify the image name so i'm gonna say go id here new go id and this is gonna give me that unique identifier so if we upload the same image twice it's not gonna get overwritten okay and i'm gonna say to string and i'm gonna give it an underscore and then i have the image name so product and image upload and file name image upload this is supposed to be and file name okay and let's see what the problem here is oh i'm missing a parenthesis here okay okay so now i'm going to get the complete file path with the image so file path string file path and again i'm going to say path and combine uploads there and the image name okay so now finally for the upload i'm gonna have a file stream fs and that's gonna be equal to new file stream and pass the file pattern here and file mode create okay and then i'm going to say await and product image upload copy to async and pass that fs there the file stream and i'm going to close the file stream at the end when i don't need it anymore like so fs close actually we need to save the new image name as well here so i'm gonna say product image it's gonna be equal to image name okay so either this no image png or whatever the new name is actually this product image is supposed to be after the if so that it saves either no image png or the actual image name okay save that and that's gonna be it for this video see you in the next one in this video i wanna test the post create product but before i get started with that i'm gonna go control comma here and open product cs and i noticed that i have this file extension validation set to the wrong property so i'm gonna cut it and paste it here for the image upload okay so anyway here i'm going to go to create new and let me just submit the form like so so i'm going to click create and we can see now that i get the error message for name and price and the category but not for description or the product image so for the description i don't get the error message here because of ck editor shake editor is going to take over the text area and this is now basically a div and so on so that's why it's not going to register but more importantly i wanted to talk about product image because it has custom validation and the custom validation by itself doesn't support client-side validation okay just the back-end validation and actually right now i didn't even choose anything so there wouldn't be any validation because it's not required but let me actually just choose that text and submit again so it's the same thing i still don't get an error here because there's no client-side validation and it's possible to add client-side validation with custom validation attribute but that's a bit more involved and i'm not gonna get into that the most important thing is to know how to create custom validation and if you want to have the support for client-side validation as well you can check it out in the documentation and i might do it uh later on for this course and have a lesson to for that in the standalone lessons section but uh that depends on a few factors okay so right now the point is there's no client-side validation for product image but there is backing validation as there is for everything so whatever validation you have here is going to work first of all on the client side if their support and then in the back end to check if it's all correct because the user can for example disable javascript okay so again let me just enter here and now i'm going to disable javascript and test it out so i'm going to right click and go to inspect you have to have the developer tools open in chrome to disable javascript and i'm going to press shift ctrl shift p and search for disable javascript enter and refresh and you can see now there's no javascript we can see that easily by this description now it's a plain text area there's no wizardwick because there's no javascript okay so if i choose a text file now here and click create you can see that now i do get the error okay and we have another problem here and that's that there are no categories when there is an error so we need to fix that as well first of all i'm gonna enable javascript so ctrl shift p and search for enable javascript refresh okay i'm just gonna hit enter here in the url so to have those categories always i'm gonna copy this line from the get create and paste it here in the post create okay so it's gonna be there if it's needed it's needed if it's not it's not so let's check again i'm gonna enter here just to refresh the page okay so once again i'm gonna say apples and here i'm gonna say some apples and the price 150 and category fruits and for the image i'm gonna choose a text file so that i get the error so create and i still have everything now here and the categories as well are there and the correct one is chosen okay so that's all good and let me choose this apple's image and click create okay there's a bit of a problem in the controller oh the error is that i don't have the web host environment in the constructor okay so let me just copy that and paste it here and here as well okay you guys probably caught that when i did this but anyway here it is so anyway let's try again okay create new and apples and some apples and 150 category fruits product image apples and create and the product has been added okay great so there's the name the price the category and we need to have the image here and this is supposed to be formatted a bit better for the price but we're gonna do that in the next video so it's all good uh in this video i'm just gonna add the rest of the products for the rest of the video okay so you don't have to follow along anymore but i need to add everything so i'm gonna add let's see what's next here bananas so bananas and say fresh bananas here or whatever and the price 299 let's say category fruits create okay create new let's see actually what's next here in the image so grapefruit grapefruit description juicy grapefruit price says 250 let's say category fruits product image actually we have so create okay next let's see grapes so grapes and the description is wonderful grapes the price is 150 and category fruits create okay next let's see kiwi so here we here and description is nice kiwi price is 350 let's say and fruits create and create new and watermelon watermelon juicy watermelon price says 50 cents let's say category fruits and create okay now on to the t-shirts so let's see we have a black shirt here so black t-shirt simple black t-shirt and price is going to be 199 let's say category t-shirts create next blue shirt so blue t-shirt and a nice blue t-shirt price is 299 category t-shirts create then let's see we have the gray t-shirt so great t-shirt new gray t-shirt let's say price says 3.99 category t-shirts create and two more to go so pink shirt pink t-shirt a pink t-shirt price is 5.99 let's say category t-shirts create and finally white t-shirt so white t-shirt description nice white t-shirt price is let's say 3.99 and category t-shirts and create okay great that's gonna be it for this video see you in the next one in this video i'm gonna get started with partination for the products here so right now i have 12 products and i can see all of them here but let's say i want to display six products per page okay so i'm gonna go to the products controller and the index section and there's no very easy way to add potential you have to add some stuff yourself and then use a package and that's what i'm gonna do and the package i'm gonna use is actually just a tag helper a custom tag helper but anyway let's see what we want to achieve here so i want to have six per page okay so first of all i'm going to say that end page size so have a variable page size is 6 which is how many items i want to show per page and i want to have a p in the query string okay so here i'm gonna say np is gonna be equal to one so now here i'm gonna save our products and that's gonna be equal to and let me just copy this context products order by descending include okay and let me bring this down just so it's a bit easier to read the whole thing i mean so now here i'm gonna say skip okay to skip some and i'm i'm gonna skip in parentheses p minus one and uh times the page size and i'm gonna say take page size okay so the first one is gonna skip zero because it's one to begin with so one minus one is zero times page size is going to be zero then the second one is gonna skip six and so on and this return here i'm gonna replace this whole thing with products to list async save that so now here if i refresh as you can see i get six and if i go here to the url and add the query string so question mark m p equals 2 i get an x x or actually 5 for some reason and why i get 5 i don't know let me see maybe i have 11 products instead of 12 let me see go to the table okay right click view data and i do i'm missing one t-shirt so i have black blue gray pink white okay let me just add another product here so let me see again gray oh and yellow i'm missing okay so actually yellow and while i'm here i can see that there's no padding here so let me just right click and inspect okay let me go to the index view products index not index but createment and let me see here okay i need a class here of pt-2 okay so just abortion class and the refresh now okay so again yellow shirt and now there's some space so yellow shirt and nice yellow shirt or let me say t-shirt here nice yellow t-shirt and price is 3.99 and category t-shirts create okay so once again if i go here to p equals 2 i get the next x and so on so that's great but i need to have the navigation here to actually do that by clicking not by the url and by the way now we can see this type of model binding in action so as you remember from before i said model binding tries to take values either from the model for example when you pass the model to the method or via route parameters or via query strings and this is a query string okay so that's this p right here so so far so good this works manually but we need it to work automatically and we're going to get to that in the next video see you then in this video i'm going to continue with the pagination functionality so if you remember from the last video i said i'm gonna be using a package so in visual studio i'm gonna go to tools and nougat package manager manage packages for solution and here in the browse tab i'm going to search for pagination and i'm going to be using this code hex pagination but i'm not gonna download it since that doesn't really do anything so i'm gonna go to product url here and here's the documentation okay so i'm actually just gonna go to the tag helper let me just find it here it is and i'm just gonna copy this whole thing and paste it in my custom tag helper file which i'm gonna create so this pagination uses a custom tag helper and i'm gonna show you later on how to create your own and we're gonna go through this one as well because it's a really good example but anyway for now let me go to infrastructure folder right click and add class and i'm going to call it pagination tag helper add that okay let me just select everything and paste what i just copied so the namespace is wrong this is supposed to be cms shopping cart and infrastructure okay so let's see what it says here this is how you use it and you have these values you can set okay so i'm going to copy and before that actually i need to add this to the view inputs file okay so because this is a custom tag helper we need to add this line so i copied it and i'm gonna go to view imports here and the paste below this one here so this one is for the built-in ones but i'm gonna need this line for the custom ones and i'm gonna say here cms shopping cart infrastructure dot all or start and cms shopping cart here okay so this is going to include all the tag helpers from shopping cart infrastructure so now let's copy this thingy copy that and in the index so product index i'm gonna paste it below the table okay so let's see here what we need we need the page count and that page target and page number and page range so let's see what these things are page count is the total of the pages what's next page target is the url number let's see okay doesn't say here so page number is the current page we're on and finally page range is how many items to display okay so we need to provide these values for the page target i'm gonna say slash admin slash products okay and for these others i'm gonna go back to product controller and set them here in the index or here that is and then pass them so i'm gonna set the page to view bag page and that's going to be equal to p and let me just recheck what they call it here so page range okay so view bag page range is going to be equal to page size whatever page size is and i need the total number of pages so i'm going to save you bag and total pages and that's going to be equal to cast this to an end so math ceiling and context products count this was supposed to be count divided by page size okay and uh i'm gonna cast this to decimal as well okay that should do it so in the index view this is gonna be view bag and total pages page number is gonna be view bag and let me actually call it page number in the controller as well so page number and page range is gonna be what was it page range here as well okay let me just copy this thing page range is gonna be at view back page range save that and let's see what we have now okay looks good enough for now and let's check out this link so you can see that the links point to slash admin slash product slash page number okay so you can um create a special route for this and so on but i'm not going to do that i want to have it i want to have the pages set by the query string as we did already with the p okay so i need to modify this tag helper a bit for that and i'm gonna do that in the next video so i just wanted to show you the links so make sure to check out where it points to now and here i'm also just going to have this as lowercase because that's the proper way to have it even though uppercase works as well and i want to center this so i'm gonna have this in a div let me just cut and paste this whole thing okay and give this div a class of d flex and w w-100 and justify content center okay so these are just booster classes and i have a course on bullshop if you're interested but anyway all these classes i'm using if i haven't defined myself on video means they're booster classes anyway let's refresh this and see what's up okay looking good but as i said we need to change this urls and also for example here we're done here we don't want to have this first on the first page or last on the last page so we're gonna take care of that as well okay that's gonna be it for this video see you in the next one in this video i'm gonna modify the tag helper a bit to suit our needs so ctrl comma and go to pagination to a helper okay and i'm gonna go more into custom tag helpers later on when we create our own but the gist of it is you have this process method which you need to override and you pass the context and the output and the this output is the point uh and that's going to be the final string okay and this guy here who was the helper this is as you can see he has some logic here and there's this var content which is a string and he has a pending to the string to get the final string at the end okay so the point is to get a string at the end and you output it with the output parameter here in the process method okay so anyway let's see this a bit so here we said we don't want this first for the first page or last for the last page so let's take care of the first first and that's this line right here okay it says page first here so i'm gonna have an f here i'm gonna say f page number is not one in that case i want to have this otherwise i don't want to have it so what is this page number let's control click it and see it's a property here in the class and this is because this is a tag helper it extends tag helper this property is automatically the the value for this property is automatically coming from the index view let me just open it so index and page number here was it yeah so page number here all in pascal case is going to get the value from this page number in kebab case okay automatically once again because this is a tag helper it extends tag helper so if that page number is one i don't want to display the first link so let's see okay it's not there anymore and if i go to p2 it is there okay so great that's good next is this link so as we said we don't want to have this url so slash admin product slash did because by our route does the id so we would need to create a custom route but i want to have this as a query string so let's see those links are coming from here okay and others like it so here it is href is equal to page target slash current page so we don't want that we do want the page target but with the p query string not slash current page okay so i'm going to press ctrl f in visual studio and current document here and i'm going to search for slash and curly brace current page curly brace and i'm gonna let's see here say find all and click here for the replacement okay so uh this is what we want it was just there for me i guess from before i'm not really sure but anyway let me just write it so question mark p equal to and in curly braces current page okay so let's uh say here replace all three occurrences replaced okay hopefully you get the same thing save that and refresh okay so if i hover over two you can see down there in the bottom left it's a query string now so if i click it i go to the next six and if i click number one here the first page i go to p1 okay so great and the first link is wrong so let me just check that out okay so we don't want this slash one here we just want the page target save that and refresh okay so one points to question mark p equals one which is correct and first points to admin slash products which is great is the same as clicking here okay really good and this last we don't want to have on the last page and we need to change the url it points to as well so let's find it that's this one right here at the end okay so again i'm gonna have an f here and i'm gonna say here if page number is not equal to page count okay in that case i'm gonna have this last otherwise if they are equal i don't need it and change the href a bit so this is gonna be question mark p equals page count save that so again this page number this page number is from here we saw that already and page count is also a property here and in the index view here is page number so the same thing but kebab case and page count okay so refresh and let's see and there's no last page now which is great and if i go to the first page now there is last and it points to p equal to two which is correct okay that's it for pertination great that's going to be it for this video see the next one in this video i'm gonna do the details action method for the products okay so i'm gonna go to pages controller and just copy the details from there so this one right here copy that and paste it here so this is going to be admin products details and some id and this is gonna be product and control w to highlight the word product here as well and products and i'm just gonna say find async here id and if product is null return not found otherwise return the view with the product okay let's create the view right click add view details template details model class product okay so here i'm going to get rid of this namespace and say for the title product details nh1 as well okay and let's see what we have here so edit and for this edit let me just copy from index from here so the one with the helper tags or tag helpers actually okay and this is just gonna be model id not item because it's not in a loop because here we have this item because we called it item in the loop okay so anyway let's see what this gives us if i go to details for the yellow shirt okay here it is so id name slug description should be html price should be formatted and the image needs to be displayed as well and the category name actually so let's see id name model slug description so this is gonna be html and raw okay model description and the price is going to be model price and to string c2 to format it category is going to be model and category name and now that i'm doing this i think i didn't include the category in the query let me see i didn't so i'm just gonna say here include and xx category and let's see now find async isn't going to work so i'm just going to use first or default async and say here where id is equal to id okay so when we're back to the view details view so category should be okay now and the image finally so for the image i'm gonna have the image source and in the source i'll say tilde for the root domain and you can see that i get intellisense here which is really good so media products and model image save that and actually let me give it a width of 200 just so it's not too big okay let's see refresh so what was the problem the description now it's fine price is formatted category says the category name and we get the image okay great and while i'm here let me just quickly in the index view change this price and image so right now it's like this and there's no image okay so let me just say here to string and c2 and for the image let me just copy since i wrote it already here so copy that line and paste it here and just have this as 100 let's say and this is supposed to be item here okay so let's see refresh okay great that's gonna be it for this video see in the next one in this video i'm gonna do the get edit method action method for products okay so first of all i'm just going to cut and paste this method above here so it matches the other controllers for no particular reason so let's same pages it's like that so for the index then details and then create and so on okay so anyway let me get the edit from here from pages and paste that down here so this is going to be products edit and sum id and this is going to be product and product and products here and if product is null return not found otherwise return the view with the product okay save that and let's create the view so add view template edit model class is gonna be product okay so let's see here get rid of the namespace and the title is gonna be edit product and h1 edit product as well get rid of h4 and hr and here i don't need the id and the name i do need slug i don't description i need and price and category and the image okay so let's first of all change this description to be text area so i'm going to go to create and just copy and paste here get rid of the input and for the category i need to pass those categories in the select list so let me go to product controller and just find that here this line so copy that and paste it here okay and from create also i'm gonna copy the this form group div with the select so copy that and paste it here instead of this one and the only difference is now i want to have a pre-selected option here okay so if i ctrl shift space you can see that the fourth override accepts the selected value and that value will be product and category id okay so let's go to edit let's say yellow t-shirt okay so categories t-shirts that's good and there's the description so we need to turn this into a wizard wig and we need to modify this image a bit so for the image first of all i'm gonna in this div just display the current image so i'm going to say here in the label current image and let me just paste from details this image source okay and i don't need this validation here and because uh i don't have that input here for the image i'm gonna pass the image value here as a hidden input so input hidden and this is going to be asp4 and image okay and for the new image in case we want to upload a new product image i need to support that as well so i'm gonna go to create and just get this div with the image upload and i'm just going to change the label to say new product image okay so hopefully that should do it for the form and i need some javascript here i need to turn the text area into wysiwyg and also to support this image preview so in create i'm just gonna copy this i'm just gonna copy these script tags so copy that and paste it here and then this a bit okay so let's see refresh okay looking good so description and the image and new image to upload with the preview okay great let me just change this value to say edit and up here change this column d4 to 10 okay great that's going to be it for this video see in the next one in this video i'm going to do the post edit product so for that i'm gonna copy this create post okay get that copied and paste it down here so this is gonna be slash edit and slash some id so i'm gonna use the id from the url and then ty d here and this is gonna say edit okay so here i have the viewbug category id in case i need it and i'm just gonna add the fourth argument here for the selected value so id actually that's a product whoops product category i did that is okay so let's see the rest if mother state is valid i'm gonna set the product slug that's fine then i want to check if this log exists but not for this particular product so again i'm gonna have here that where and say where x x id is not equal to id okay so for the image upload now i don't need this variable here i'm going to get rid of that and again i want to check if the image upload is not now because it's not mandatory to upload an image when editing so first i get this uploads there i need that but then i want to check if the product has that no image png image because i don't want to remove that image okay so now here i'm gonna say if not string equals and product image so if product image isn't no image dot png in that case we need to remove the existing image and upload a new one okay so i'm gonna copy and paste that line here and call this old image path and i'm gonna combine uploads there with the current image so product image and then delete it so i'm just gonna make sure it exists so if file exists and let's see here i don't get any help here so i'm just gonna say here system dot io file exists and pass that old image path and copy this line and paste it here so if it does exist i'm gonna delete it i'm gonna change exists to delete okay now we need to upload a new image so i'm gonna say this string image name here and the rest is the same as it was so the only difference is that we need to remove the existing image if we're uploading a new one and if the existing image is no image png we don't want to remove that okay so this is going to be context update instead of add save changes async and the product has been edited and return to index that's fine okay looking good save that and i'm gonna start the server so control f5 okay here it is so i'm gonna go to admin slash something and then go to products so let's add this yellow shirt for example i'm gonna go to edit and say yellow t-shirt tool here and two here and for the image i'm gonna choose gray shirt let's say and click edit and the product has been edited but the image isn't changed so let me go to edit okay let's see what's up in the edit file and the problem is that i'm missing the multi-part the yank type that is here okay so anyway let's uh refresh this page and now i'm gonna get rid of these twos just to have it back to normal okay so again i'm gonna choose the gray image and edit and here it is okay and hopefully the yellow image has been removed let's check so in media products expand this a bit okay i don't see any yellow t-shirt here or yellow shirt so seems to be working fine i'm just gonna re-upload that yellow t-shirt okay great and let's just try to change the name to an existing one so let's see great t-shirt and the product already exists okay and if i go back to the list this is still a yellow shirt okay so it's all good that's gonna be it for this video see in the next one in this video i'm gonna do the delete product method so for that i'm going to go to pages controller first and just copy delete from here so this one copy that and paste it here so this is going to be admin products delete and some id okay so let's see here this is supposed to be product and product and products i'm going to copy this product paste it here so a product is now temp data error the product does not exist else context product remove product save changes async tem data success the product has been deleted and redirect back to action okay so this is all good we just need to add that delete image functionality in here to get rid of the image as well okay so for that i'm just gonna go up here and copy this block of code so copy that and paste it here in the else okay so we're messing the uploads there i'm gonna get that as well copy this one and paste it in here so that's it is the same thing again first of all we want to check if the product image is not no image because we don't want to delete no image png and then we do the deletion okay so hopefully that should do it let me add a new product in here because i don't want to delete one of these let's say here test shirt and just some generation here price can be 299 whatever and the t-shirts and just upload a t-shirt so create and here it is and if i go to delete okay and the product has been deleted and it's gone from here okay so great and if i just check the images here so there's that gray shirt the original one for the product we have and there are no other gray shirts here okay so that's all good and by the way because of that confirm deletion class on delete of course if i say cancel it's not going to go through same as before okay that's going to be it for this video see in the next one in this video i just briefly wanted to go over the scenario of deleting a category so each product has that category id right so that category id is the foreign key to a category and when we created the products the product model that is we specify that foreign key which we can see if we open the database so dbr products view view designer actually okay so it says here down here the constraint foreign key constraint category id references categories id so the id column in categories and on cascade delete okay and that means that if you delete the category all the associated products will be deleted automatically so let's see that in action i'm gonna go to categories and create new and just call it test and i'm gonna go to products and create new and just create a test shirt with some gibberish here and some price category test and some shirt create okay so we can see here that the category is test for this shirt so now if i go to categories and i delete this category the shirt is no more that test shirt okay so it's deleted automatically so this is uh a great thing and the only thing that's not deleted is the image okay so there's no mechanism to delete the image automatically that doesn't make sense so you can see here i have a gray shirt and a gray shirt so one of these is the one for the product we just deleted so to delete the image as well you would need some additional logic for example you could create a folder for each category here in the media folder when you create a category and then have the products in there the images and so on and then delete that folder for example when you delete the category or whatever you know that's up to you the logic for that but the point is i wanted to show you that cascade deleting action which deletes all the associated products so if we had 1000 products it would delete them all okay anyway that's gonna be it for this video see in the next one we are done with the admin area so in this video i'm gonna get started with the front-end section and create the pages controller and the index method so in controllers here i'm gonna say add controller empty and call it pages add that okay here it is i need to get that context db context dependency here so to do that i'm just gonna copy from wherever somewhere i have such as this one here so copy that and import infrastructure and i need to change the constructor name as well to pages controller okay change this method to be async so async task like so okay so here for the comment i'm gonna say get forward slash so the root or slash and the slug page slug okay so for example the routes we have now let's see the one route actually for the front end which is this one here with this route it will work like slash pages some action and i don't want that i want the root domain to be the home page and to go to other pages by going to row domain slash the page log which is normal so i'm going to need to create another route but first of all let's take care of this one here this method here and i'm actually going to call this page not index and i'm gonna pass a string slug here okay so first of all i'm gonna check if slug is null so if slug is null that means we want to get the home page so i'm gonna say return view and await context pages where x slug is equal to slug and first or default async okay and let's import this ef core otherwise we need to get the specific page via the slug so i'm gonna say here page page is gonna be equal to this again so i'm just gonna oops copy that and paste it here and i want to check and let me actually just import this first of all and i want to check if the page is null so if page is null if it doesn't exist i'm gonna return not found otherwise i'm gonna return the view with the page okay save that and let's create the view so right click add view page and the template can be empty really for this view and use a layout page checked so i want that okay click add and here it is so for the title i'm going to say cms shopping cart here and i'm going to specify the model so i'm going to say at model page okay and the content here i'm going to say html raw and model content save that looking good so once again i need to specify the route because i want it to be either the road domain or slash the page and that's not supported now so for that i'm gonna go to startup and i'm gonna copy and paste this one at the top but it's gonna look a bit uh different to this one so i'm gonna get rid of this just have the closing parenthesis there in the semicolon okay so now i'm gonna specify the name straight away without this name key here basically so i'm gonna call the route pages and the next argument to specify is the route so the route is going to be in curly braces i'm going to say slug and the question mark to make it optional and now i'm going to set the defaults so i'm going to say defaults and new and controller is going to be pages equal to pages the action is gonna be equal to page okay let me just bring this back a bit like so so that should do it and by the way when you specify routes you always go from most specific to least specific okay and this goes for any platform asp or not so in this way this route will first be checked if it's possible to do something with it if not then this one and then finally this one okay so once again you always go from most specific to least specific anyway let's see this in action now if i go to the root let's see what happens oh here i'm saying equal to slug and this should be equal to home so if slug is null it's automatically the home slug that we want which never changes okay save that and again refresh and here it is this is the content of the home page page okay and if i go to let's say about us which i believe exists here it is about this page and if i go to some page that doesn't exist and not found is returned okay great that's gonna be it for this video see in the next one in this video i'm gonna make it so that this main menu displays the actual pages okay because right now this is hard coded in the main layout let's see so shared and layout and here it is okay so to do that i'm gonna use a view component and view components are a part of sp they are kind of like partial views but you use view components when you need more c sharp logic okay so anyway let's uh create that view component so to create it i'm gonna right click infrastructure let me see where it is here it is so right click add class and i'm going to call it main menu view component okay so same with the attribute the custom attribute we created you're supposed to call it whatever you want to call it and add this view component suffix so add that and this should extend view component i'm gonna import it okay so the first thing i want to mention here is that you get the dependencies through the constructor so same as with controllers okay so to do that i'm gonna copy from pages from here just copy that and paste it here and just change the name of the constructor okay so that's how you get dependencies and the second thing i want to mention is that view components have nothing to do with either requests or model binding or whatever okay so they are their own thing and you supply them what you want to supply them here the data to work with okay so anyway i want to display pages so to do that i'm going to use a method of view component called invokersync okay so i'm going to say public async task and the type is going to be iview component result okay and it's going to be called invoke async so this is the method you use with view components either invoke async if it's asynchronous or just invoke if it's synchronous and with view components you can return strings and so on but that doesn't really make much sense i'm not going to go into that with view components you're supposed to return a view okay so i'm going to say return view here and the view by default should go into the shared folder components and then the name of the view component and then the view itself should be called default okay and we'll see that in a minute so anyway i'm returning the view here and i'm supposed to return some data with this view as well so for that i'm going to say var pages and this is going to be equal to a weight and i'm going to have a method here column method which i'm gonna call call get pages that is async okay and i'm gonna show potential fixes and generate this method so here it is and i'm going to say that type for task is a list of pages and another diamond bracer and this is gonna return the pages so i'm gonna say return context pages order by and i want to order by sorting and say to list async okay and import tf core save that and that should do it for actually past pages here so that should do it for the view component the class that is okay so once again to recap you get dependencies through constructor through the constructor same as with controllers and you need to have a method here invoke async if it's asynchronous or just invoke if it's synchronous and you have your logic in this method and return the view which is supposed to be in shared components view component name default so let's create that view now i'm gonna go to shared right click go to add folder call it components and in here create another folder with the name of the view so main menu and then create a view the name will be default and i can leave this user layer page checked it doesn't really make a difference i'm going to add okay so here it is i'm going to get rid of everything controller just get rid of everything and for the model i'm going to say i innumerable page right so that's what we said here so i'm gonna loop through that and the display leads for each double tab so for each var item and model i'm gonna have ali with the class of nav dash item and inside of that have an a with the class of nav dash link and let's say text dark as well and to specify the url i'm going to say asp area is empty asp controller is pages asp action is page and the route parameter is a slug in this case right because we set so here so i'm going to say sp route slug and that's going to be equal to item slug and a itself is gonna say item title so the title of the page okay looking good so finally we need to invoke this view component in the main layout i'm going to get rid of this list here and i'm going to say await component and invoke async and the name of the component without the suffix so main menu okay and let's see what we have now refresh and here it is cms shopping cart so that's coming from here and home home page contact quantum page services about us okay great the only thing i want to modify here is i don't want to display the home link menu item that is in the main menu because this already links to home so to get rid of that in the default view for the view component i'm just gonna have an f here and say if item slug is not home in that case i want to create a li otherwise i don't so cut and paste okay refresh and here it is great that's gonna be it for this video see in the next one in this video i'm gonna create the products controller and the associated index method so i'm going to right click controllers here and go to add controller empty and call it products okay so here it is and i'm also going to open the products controller from the admin area so i can copy paste some here it is just make sure you're working in the right file okay so anyway get this db context first of all we always need that and they open pages that was supposed to be products so copy actually this is fine here i'm gonna copy just the constructor name and using okay so now for the index i'm gonna copy this uh index from products so i'm just going to copy the whole thing and paste it here so this is going to be slash products and index name is fine and i want this p here for page and again here i want page size to be six so same as before and i'm gonna get rid of this include category here i don't need it and the rest will be good so if i just import here ef core for this tool is async and that would hopefully do it okay so now i'm gonna create the view and i'm not gonna use any predefined template so i'm just gonna create that with the layout page and call it index that's fine okay so here it is the title is gonna be products or yeah products is fine and the model is going to be innumerable of product okay and to this h1 i'm gonna give a class because this is the front end so let's just like spice it up a bit you know of display four and some bottom padding and change this index to say all products okay now i'm gonna have a row and now i'm gonna loop through the list the innumerable that is so for each of our item in model i'm gonna have a div with the class of call four call dash four and in here first of all i'm gonna have the image so the source is gonna be tilde slash media slash products and item image and i'm gonna give this image a class of image fluid okay ctrl shift enter to go to new line and then h4 here now for the item name now i'm gonna have a div for the content or the description in this case so html raw and item description and i'm gonna have a p for the price and i'm gonna say item price and to string c2 to format it and finally another p for the add to cart button or link that is so i'm gonna have an a here and get rid of the href actually for now i'm just gonna have it linked to hash and when we create the card functionality i'm gonna modify this so for now this is just gonna say add to cart and i'm just gonna give it some classes to style it a bit so btn and btn-primary okay save that so let's see now if i go to slash products and it seems i need to restart my server the application that is so control f5 okay so let's try again go to slash products and here it is or here they are okay so we get six and um so far so good that's going to be it for this video see in the next one in this video i'm gonna add the products by category method so that we can get the products by category instead of just getting all the products okay so for that i'm gonna copy this index method and call it here products by category and i want the url for this to be slash products slash category okay so as it is now with uh route we have defined this would be product slash products by category slash the category and i want this url so we're gonna need to create the route for that but anyway first we'll deal with this and this np one i want it because of pagination but i also need here to get that category slug okay okay so in here first of all i want to get the category by slug so i'm going to say category category and that's going to be equal to context categories where slug is equal to category slug and first or default async and they're supposed to be a weight here and import category as well okay and just to make sure it exists i'm gonna say if category is now redirect to action index so if the specific category doesn't exist we're gonna redirect to all products okay anyway now i have this in page size 6 that's fine but for the products i want to say where here so where category id is equal to category id just indent this like so okay so next i get a page number in the view bag the page range and the total pages this needs to have aware here as well so just get this where to get the correct count like so and i also want to pass the category name to the view so i'm going to use view back for that as well and say category name here and that's going to be equal to category name okay so let's set that route now to the startup cs file and see if this works so far so here and that's gonna come after pages and i'm gonna duplicate this pages route so this is gonna be products it's gonna be called products that is which can be anything but the url itself is gonna be products slash and category slug which is not optional there needs to be a category slug and the controller is products and action is products by category okay so let's see if this works i'm gonna go to products and let's say fruits and there's no view so let's just create that view now okay so i'm just gonna copy the index view and call it products by category yes so this is all good i'm just going to have that category name here that should be the only difference so view bag and category name okay save that then let's refresh check now and here they are okay looking good and if i go to t-shirts i get the t-shirts and if i go to some gibberish category that doesn't exist and that gives me an error okay i'm gonna see what's up with this now and get back to you in the next video okay see you then in this video i'm gonna add pagination to the views and before that to fix that last error from the last video is just that i'm missing the return here okay that's it so anyway back to pagination and for pagination i'm gonna copy from admin views products index where i have it already so copy that and paste in products and index okay inside of the div so the total pages i'm getting from the method and the target is going to be slash products page number i'm getting as well and the page range i'm getting okay looking good save that let's refresh and see what happens and nothing happens so what do you think the problem is the problem is that in this view imports we're not importing custom tag helpers okay so i'm gonna go to the admin one and copy this line and paste it here as well save that let's check now and here it is now so let's see if i go to the second one okay i get the fruits if i go to the first one i get the t-shirts if i go to last it's good again and if i go to first it's good okay great that works for that and let me copy and paste this for products by category as well so inside the dev again okay so now it's kind of the same thing but i need to change this page target a bit because this isn't slash products a slash product slash sum slug right so how to get that sum slug here i'm gonna get it through view back so i'm going to say view bag and category slug and they need to have this in the method so copy this and in product controller products by category down here i'm going to save you by category slug is going to be equal to category slug save that and let's see now so if i go to fruits there's pagination but i only have six fruits and i'm saying i want six per page so that's it okay so the problem here is first of all i don't want this one here in case there's only one page and that's actually the only issue but i want to check if this actually works so i'm gonna change page size for by category to three or let's say even two and refresh okay so i have six fruits and i get three pages here so that's correct go to the second one okay third one looking good first good and last works fine okay great i'm just gonna have this back to six and in here i'm just gonna have an if so i'm gonna say if view bag total pages is greater than one in that case i want this pagination div otherwise i don't want it okay so let's refresh and see and there's no pagination here and if i go to all products the pagination is there okay and we can add this for all products as well there's no need to for this particular product because this is a course and we know that we have 12 but anyway let's just do it okay and refresh and it's still there as it should be for all products okay great that's gonna be it for this video see in the next one in this video i'm gonna create a view component to display the categories here so the idea is i want to have categories here in a sidebar basically and the products to the right okay so i'm gonna go to infrastructure right click go to add class and i'm gonna call this components categories view component okay so here it is and i'm gonna copy from main menu of your component since it's kind of the same thing so just copy the whole class body and paste it here just change the constructor name and have the main class extend view component okay so let's see here first is the dependency ejection and then this invoke sync so this is going to be our categories and i'm going to call this method get categories async just copy and paste that here and copy this category categories paste it here and this is going to be category not page okay and import models and import ef core and this is going to be categories as well save that and that should do it for the class itself and now on to the view so in shared components i'm going to create another folder called categories so same name as the actual view component and i'm going to copy this default and paste it in categories okay so open the right one and i'm gonna close this main menu view component so anyway in here first of all i'm gonna get rid of this if i don't need it and i want to have a ul here so i'm going to say ul and give it the class of list group and i'm going to have one lay in here to display all categories so i'm going to say li and give it a class of list group and item and have an a in there so i'm just going to copy from here and paste that so this one is going to be for all the products okay so sp area is going to be empty controller is going to be products and i'm not going to have an action so it's going to default to index and i'm not going to have the route parameter either so get rid of that and this is going to say all products like so and i'm gonna copy this a and paste it here for the loop and let me just end the ul after the loop and in then this back a bit so shift tab okay get rid of this closing ul there okay looking good so now to modify this a a bit products controller and now i do need the action so action is products by category and i need a route parameter as well so sp dash route dash and category slug is called okay so that's let's see in startup cs this right here okay so category slug is going to be equal to item slug and this is going to say item name this should be and it's not because this is supposed to be category here okay so anyway item name okay looking good the last thing to do is to call it in the layout in the main layout so here in this main element i'm going to copy this weight component from up here so here in domain i'm going to have a row and the div of call dash 3 and paste in here that categories view component and and i'm gonna have a call here for render body which should take up the remaining available space okay looking good let's see and here it is and the length seem fine it just looks like crap so let me just oops let me see what's up with that yeah this is supposed to be a list group item not nav item so list group item let's see now okay looking better so all products points to this page and t-shirts to t-shirts and fruits to fruits actually from fruits or t-shirts this is defaulting to where it is actually not to the index so i'm gonna say here asp action index for some reason i was sure it would point to index okay so if i go to t-shirts and then to fruit it's all good and all products points to slash products now okay great that's gonna be it for this video see in the next one okay guys we are moving along great and the time has come for the cart so for the cart i'm gonna first of all create a controller so add controller empty and call it cart and for now i'm just going to add the db context dependency in here because i want to do something else in this video so i'm just going to go to pages and get the db context dependency and just paste it here and change the constructor name and import this using okay and another thing i want to do is create a class called session extensions and that class is going to be used to store complex data in sessions because for some reason asp by default provides sp core that is provides support only for adding ins and strings to sessions as it is and to add more complex data such as lists for example you actually need to write that extension and then serialize them and deserialize them so anyway let's create that now it's not a big deal so in this infrastructure folder i'm gonna have it there and you can have it anywhere so i'm gonna add a class and call it session extensions okay and here i'm gonna have two methods so what i want to do is turn that complex data into json so i'm to say here public static void and i'm going to call it set json this method and for parameters i'm going to say this and i session session and the string key and object value okay so we need the session and the key and the value and the class is actually going to be static as well so now i'm going to say session and set string key and the string value so the string value is going to be json convert from newtons.json and serialize object and that value okay so that's it for setting and now forgetting so i'm just gonna copy this method and i'm gonna call it get json and this is gonna return a type and have that here as well and i need just the key for get so i'm going to get rid of this method body and i'm going to say var and session data and that's going to be equal to session and get string okay and now i'm going to say return and if session data is now i'm gonna return the default type otherwise i need to deserialize that session data so i'm gonna say json json convert and this serialize object and pass the type here and session date okay so with this in place you can now use complex data for sessions okay so anyway we're ready to move on now so that's gonna be it for this video and see you in the next one in this video i'm gonna create a class called cart item and that class is gonna represent one product in the cart okay so the cart is gonna be a list of these cart items so to do that i'm gonna right click models and go to add and class and call it cart item okay so in here i want to have the id so i'm gonna say product id and the string product name and end quantity and decimal price and decimal total and for this total i'm gonna say that this get returns quantity times price okay and we'll get rid of set and finally i'm gonna have a string image okay and i'm gonna be getting this data this properties from the product model so for that purpose i'm gonna create a constructor in here adjust so the code is cleaner when adding a cart item and i'm not really sure what to just press there so say tor and actually this is supposed to be inside of the class i went outside by accident okay so this cart item and i'm gonna pass product here okay and now for the body i'm going to say that product id is equal to product id and so on for the rest so product name is going to be equal to product name and price to product price for quantity i'm gonna say one and image is gonna be product image save that okay looking good that's gonna be it for this video see in the next one in this video i'm gonna do the index method of the card controller and this method is gonna be synchronous so i'm gonna go straight to the body here okay so what i want to do here for the cart index is i want to have a list of those cart items we just created which are either gonna be in the session or not okay so if they are in the session then get them and if they're not then just create a new list so i'm going to say list of card items cart and in this session extensions class we extended i session right so now i can access these methods set json engage json by saying http context and session so now i'm gonna say get jason and i want to get the list of card items and the session is going to be called cart okay so we don't have that add product method yet but when we do we have it the session is going to be called cart okay so either get the list serialized list from the session or if it's null then create a new list of cart items okay so now to the view i can just pass this card that's fine but let's create instead a view model because we haven't done that yet so let's just have one pure view model in the project because so far we use this category page and product classes as both dtos and view models okay so once again dtos are data transfer objects and they represent the actual table in the database and view models are the classes you specify for a view to use as the data for the views you get that intellisense and so on okay so anyway i'm gonna right click mouse and go to add class and call it cart view model like so add that so here i'm gonna have two properties one is gonna be a list of card items and i'm gonna call it cart items and the other is gonna be grand total so prop double tap decimal grand total okay great so in card controller here i'm gonna say cart view model cart vm and that's going to be equal to a new card view model and cart items are going to be card and grand total and once again i could have just passed this car to the view and calculated the grand total in the view as well but let's just use a view model just to have that as well and it's a bit cleaner so the grand total is going to be a card sum of actually let me use x here of price times quantity and return that view model okay cart vm i have a semicolon here okay looking good let's just create the view now just a basic view for the index and we're going to modify that view later on but now just so we have something so index and it's going to be details and model class is going to be a card view model and use a layout page okay add that here it is and i'm not gonna modify the view now i'm just gonna add an f here just to check if there are any items if not a display a message for now so if model cart items count is greater than zero then i'm gonna have some html for the cart else i'm gonna have an h3 whoops with the class of display 4 and text center and say your card is empty okay and i'm just going to add a comment here for the index to specify the page so this is going to be slash get slash card so let's see slash cart i'm asking for session here but we haven't added it in the startup file okay so anyway we're gonna do that in the next video okay see you then in this video i'm gonna enable sessions so to be able to actually use sessions you need to enable them in the startup cs file so i'm gonna go there startup cs and in the configuration method configure services method that is above add controllers with views i'm going to say first services and add memory cache to use that memory cache and then i'm going to say services and add session okay and also in the configure method below this user routing let's say i'm going to say app and use session like so save that so hopefully that should do it let's refresh and see and here it is your card is empty great okay so that's it for just enabling sessions but i wanted to cover an option in here when adding a session so i'm going to say options fat arrow and curly braces and now here i can specify the timeout okay so options and idle timeout so when you want the session to clear so i can say for example time span and let's say from seconds and two so this would clear the session in two seconds for example okay and let me copy this and comment out this first one and you have for example from days hours minutes and so on milliseconds okay so from days to in two days and so on so i'm not gonna be using this i think i'm just gonna have it commented out here for your reference just so you know this exists okay that's gonna be it for this video see you in the next one in this video i'm gonna add the add to cart method so i'm gonna copy this index one paste it down here and the comment is gonna be slash card slash slash sum id and i'm gonna call the method and this is going to be async so async task i action result okay and i'm going to get rid of the whole body here so i'm going to get the id in here so first of all i need to get the product so product product and that's gonna be equal to context products and find async id and just have a weight here as well okay so get the product and now again i need that list of cart items either from the session if it exists or create a new one so i'm going to copy from up here and paste that in here and now i need to get the particular cart item so cart item cart item is going to be equal to cart where so where product id is equal to id first or default and now i want to check if the cart is null the cart item i mean else okay so if cart item is null i want to add the product the cart item to the cart but if it's not null i want to increment the quantity by one okay so if it's now i'm gonna say cart add and new cart item and i'm gonna pass product in here so let's control click this cart item okay so that's where this constructor comes in you don't have to have this constructor but it just makes for cleaner code and while i'm here i'm gonna add an empty constructor as well in here just so nothing breaks along the way okay so i'm adding a new product here if it doesn't exist and if it does increment quantity so cart item quantity plus equals one okay and now i need to set that session for the card so i'm gonna say http context and session and set json and by the way so this cell json is our method from session extensions but there's also this set method you can use to set uh simpler types as i talked about before such as integers or strings but for complex data types such as lists you need to serialize them so set json and it's going to be called cart the session and pass the cart in here and finally return a redirect to action index okay so now if i go to let's say all products i'm supposed to click here and add a product so i need to modify these anchors so i'm going to go to view and products index amp products by category and the modify this is a bit so right here i'm going to get rid of this href and i'm going to have asp controller which is going to be cart and sp action which is going to be add and asp route id which is going to be item id and i'm going to copy this a and just replace this one here in products by category okay refresh the url seems fine so if i click add and great i'm taken to the cart page and i can see that there is something in the cart we still need to modify the cart index view but it's working okay that's gonna be it for this video see in the next one in this video i'm gonna modify the cart index view okay so i'm gonna right click inside the method and go to view here it is so get rid of the namespace and the title going to be card overview and copy that for the h1 as well actually i'm going to have this h1 inside of this so if there is something in the cart then something else this h3 okay that's good and i'm gonna get rid of everything but the h1 inside of this f so first i want a table and it's going to have a class of table as well and now we have a tr so th product and just ctrl d a few times so product quantity and then i'll have some actions to add and remove the product so i'm going to leave this empty and price and total and that should do it so get rid of these two and now i'm gonna loop through the model so for each of our item and model cart items whoops okay so for each i'm gonna have a tr and this one is gonna be product name and quantity and here i'm gonna have those actions so i'm gonna have an a with the class of btm btn-sm and btn-primary and sp action is gonna be add and asp route id is gonna be item id product id that is and it's gonna say plus okay so to add one basically and copy this two more times this one the class actually is gonna be success bt and their success and asp action is going to be decrease and minus here so you can add one with the plus remove one with minus or remove the product entirely from the cart okay so this one is going to say remove and beat the end danger here and remove here as well save that so the add method we have and we still need to create the decrease and remove ones okay so let's see price and total we have left so item price to string c two and the total is the total for this particular product so if there are three items of the same product does the total for that not the whole cart okay so i'm gonna do that in here to get that sum i'm gonna say model cart items where where product id is equal to item product id and get a sum of that particular product so where quantity not where but i mean so some quantity times the price and two string c2 that as well okay and finally i need the grand total of the whole thing so outside of the four inch after the 4-h that is i'm going to have a new tier with the td of class text right and call span 4 and this is gonna say grand total and uh i said before that i can get the sum of that grand total in here in uh this way but um i'm already doing that in the card view model okay so this grand total right here which i'm setting here so i can just use that okay so anyway this is going to say model and grand total and to string c2 to format it save that okay and i also want another tr here for the clear cart and checkout buttons and let me just copy this td i'm gonna have one td in here again with two a's so the first day is gonna have a class of btn and btn their danger and sp action of clear so to clear the card entirely and it's going to say clear card here and the second day is going to have an href to hashtag and btm btm primary and this is gonna say check out okay so the clear cart a clears the cart the uh an action method so clear action method and the checkout is gonna go to paypal later on okay so so far so good let's uh refresh here okay the card is empty so all products add the yellow shirt here it is and let's say a white shirt okay and some fruit as well some melons and let me add the watermelon again okay so you can see it's working fine one yellow t-shirt 399 and as a total white shirt same thing and watermelon two watermelons at 50 cents each so the total is one dollar and the grand total is correct as well okay looking good and i can also click here so let's add another yellow t-shirt let's say and the grand total is changed quantity is 2 and the total for yellow shirt is correct as well okay great that's gonna be it for this video see in the next one in this video i'm gonna do the decrease method so i'm gonna copy this add ctrl d this is going to say decrease in sum id and decrease here as well for the name okay so let's say here i don't want this product i don't care about the db context at all in this method just the card okay so if i'm doing a decrease then that means that there is data in the cart the card session exists so this is going to be equal to the card session card is then i want to get the card item next i want to check if the quantity of this particular card item is greater than 0 greater than 1 that is so i'm gonna say if car titan quantity is greater than 1 in that case i want to decrease it so i'm gonna say minus minus cart item quantity else if it's one then i want to remove the product the card item from the cart not just decrease it by one okay so if it is one then i'm gonna say cart and removal x x product id equal to id then i need to set the cart session again and after that i want to check if there are any items in the cart at all okay so maybe we had one product in the cart and we removed it so this removal kicked in for the cart item and then there's nothing in the cart so in that case i want to clear the cart session so i'm gonna say if cart count is zero in that case i'm gonna say http contact session and remove that card session okay and finally redirect to index so let's see if this works refresh okay all products add a yellow shirt and another and let's add a white shirt so if i go here to decrease okay i get one here now it was two before the quantity again okay now there's only this white t-shirt and if i remove that and the quantity is one so now when i decrease the card should be removed from session because there's nothing in it and your card is empty great that's gonna be it for this video see in the next one in this video i'm gonna add the remove method and before that let me just get rid of this async task here because this method is not asynchronous okay and also here i'm setting the session here and then clearing it if the count is zero and there's no reason to there's no point that is to to first saturn it if you're gonna clear it anyway so i'm gonna have an else here actually and then uh set it in this else okay so after this remove if the cart is zero then just remove the cart otherwise set it again okay anyway on to the remove method i'm gonna copy this decrease one so this is gonna say remove and some id and remove here okay so again i need to get the card from the session and i don't need to get the particular cart item because they just want to remove it so get rid of all of this oops just leave the remove all here to remove from the cart and i should do it okay save that and let's see go to our products again let's add one yellow shirt and let's add some kiwi okay so 399 and 350 and this is the total so remove yellow shirt and seems to be working fine and remove this last product with quantity of one and card is empty okay great that's going to be it for this video see in the next one in this video i'm going to add the clear cart method so i'm just going to copy this remove one and this is going to be slash car slash clear and clear here no parameters and here i'm just going to say http contact session remove card so copy that line get rid of everything and return a redirect to action index okay so let's see if this works go to all products and let's add a few products so yellow shirt and let's say kiwi and clear cart and great the cart is empty and we are redirected back to the cart index so it's all good that's going to be it for this video see in the next one in this video i'm going to create the small card view model and view component so the point here is that i want to have a small cart overview here below the categories which is gonna display the total number of products and the total amount okay so let's get to it first of all in the models folder i'm going to create a new class and call it small cart view model and in here i'm gonna have one property and called number of items and another decimal called total amount okay so now on to the view component i'm gonna right click infrastructure and go to add class and call it small cart view component so this is gonna extend view component and it's going to have that invoke method so public eye view component result is the return type and i'm going to call it invoke so before we use invoke async and now we just invoke because it's not asynchronous okay and this is gonna return the view at the end so first of all here i need to get that session data so i'm going to say list card item card and that's going to be equal to http context session and get jason so list cart item and the session is called cart and now i'm going to initialize that view model to null so small cart view model small cart vm i'll call it and that's going to be equal to null to begin with okay so first i want to check if the cart is now or the card count is zero in that case actually i'm gonna say that uh small card vm is null and here i'll just declare it else small card vm is going to be equal to new small card view model and then here the number of items is going to be equal to cart and sum of the quantities and the total amount is going to be equal to carton sum quantity times price okay and finally return the view with small card view model save that now to create the view i'm gonna go to views shared components and in components create a new folder and call it small cart and i'm just going to copy this default from categories or main menu whatever you have handy so small cart default view i'm gonna get rid of this ul so the model is gonna be small card view model and first of all i want to check if it's null so if model isn't null then something but if it is null i want to display a message so this is going to be a p with the class of lead and am there 0 margin 0 and it's just gonna say your cart is empty okay but if it's not now then i'm gonna have a p and say items in cart and then i'm gonna have a span with the class of badge and badge primary and this is going to display the number of items and i'm gonna have another p that's gonna say total and the b tags here and this is going to be the total amount so at model total amount and to string c2 to format it okay and now i'm gonna have two ways here to view the cart and clear the cart so a with class of btn and btn primary and mb-2 margin bottom two and asp controller card and asp action index and this is going to be view card and have a br here and let me just copy this a and paste it here so this is gonna say clear card and action is gonna be clear and i'm gonna change this primary to danger okay save that and get rid of dmb-2 actually this looks good finally i need to invoke the view component in the main layout so in the main layout here in the call actually in the call 3 below the categories i'm gonna have a div with the class of small card and now the boosh of classes so bg success and mt-3 p3 and text white so this custom small card class can be used either for styling or to get to it via ajax which we'll need to do later on regardless so we might use it for styling we we might not i'm not sure now we'll see how this looks but we will need this class to be able to access it with javascript okay because we're gonna need to update this dev when we add to cart via ajax which will be added in a bit but anyway invoke the component here so just copy this and paste it there and this is gonna be small cart save that and let's see what we have okay your cart is empty great and if i add something so total is 3.99 one item if i plus here i have two items so 798 is the total same is here and let's add the watermelon okay so three items in cart and the view card goes here and the total is correct and clear cart works okay great that's going to be it for this video see in the next one in this video i'm going to start adding the edges functionality for adding products so first let's modify these views so i'm going to go to views and products index and products by category okay so first of all for this a here i want to add a custom data attribute so i'm going to say data dash id and that item id so i'm going to use that in the ajax call to create the correct url so slash card slash add slash sum id okay and now let's uh add the needed stuff to display that the product has been added to the cart inside of the div so for that i'm going to have a devin here with the class of ajax bg so eric's background basically and in here i want to have an ajax loader image and the message the product has been added so for the image you have in your course files this ajix loader so just drag it to actually before we drag it let's create an images folder for that so it's in a proper folder so add new folder and images so this images folder should hold static images that have to do with design and so on okay so anyway grab this ajax loader and paste it here okay and i'm gonna drag it to the ajax bj div like so and have the p as well so the p is gonna have a class of lead and alert and alert success and text enter and it's gonna say the product has been added like so okay save that and let's see refresh okay here it is looking good so far i'm gonna just right click and inspect just so i can see it here as well in case i want to remove a class or add a class or whatever so let's style this a bit i'm gonna go to site css and down here i'm gonna set say div ajax bg and background is gonna be rgba255 two five five two five five so white and point eight here for opacity okay and the position is gonna be absolute and top zero left zero and with one hundred percent and height one hundred percent as well and i'm just going to give it a z index of one okay so let's say refresh and shift ctrl shift r to refresh to clear the cache okay looking better and now for the image i'm gonna copy this and paste it here so for the image it's gonna be position absolute and top let's say twenty percent and left fifty percent and z index two and to center it horizontally i'm gonna say transform and translate x minus fifty percent okay save that ctrl shift r here it is in the center horizontally okay and the p as well so copy this so this is going to be p and that's going to be position absolute and top 50 pixels and the index of two okay ctrl shift r again okay looking good and to begin with i'm gonna give this aj xbg div a class of d n so display none and p as well okay refresh so when we click add to cart i want to get rid of this dnn and have this ajax loader and then when the cart is added i want to display that p okay so so far so good and let me also copy this address bg div to products by category so here as well and this date id as well okay great that's gonna be it for this video see in the next one in this video i'm gonna add the adrex code for that latest request okay so in the index view down here i'm gonna have that section scripts and script tag in here and jquery ready okay bring this back a bit so i want to respond to click for this a add to cart and i'm going to give it a class as well here add to cart like so okay so a add to cart class and click function so first of all i'm gonna have e in here for event and say prevent default like so okay so first i'm just gonna have that basic functionality of adding to the cart and updating this small card here and then i'm going to add code to get those success messages and so on the ajax image and the product has been added p and so on okay so first of all i need to get the id which is this uh date id here so i'm gonna say let id and that's gonna be equal to this and data id like so and then i'm going to create that status request so get and the url is going to be slash card slash add slash and the id i'm not going to pass anything here so just an empty object and have a call back here and data in here for the argument okay so i want to replace the contents of this small card here with the data that i'm gonna get from the cart ad so i'm gonna say div and small card class so that's this small card class right here okay and html data and that's the gist of it for the ajax in here this series call so we just need this id and that's it we make the get address request and that's it so now the issue is that in the cart add card controller add method let's see add actually where is it here it is okay so here the issue is that we are returning a redirect to action index card index which is fine if we invoke this method on the cart page with the plus sign but now because we want to make an edius request if i'm adding from here then i want to return that view component view the small card view component okay so the way i'll do that is i'm gonna say here if and i'm gonna check the request i'm gonna check if it's not an ajax request if it's not i'm going to return redirect to action index and if it is an ajax request then i'm going to return that view component okay so i'm going to say if http context request and headers actually this is supposed to be in square brackets so in here i'm gonna have a string and x dash request the dash with okay so if this isn't equal to xml http request in that case i'm gonna return this so i'm just gonna paste it here like so and if it is an xml http request so ajax then i'm gonna return the view component small cart okay so let's see if this actually works i'm gonna refresh okay so i'm gonna click add to cart here on all products because we only have this in the index view and let me actually just copy this from the index view over to products by category as well since it's the same thing and just add to this a here that add to cart class okay so let's check it out refresh again so on all products add to cart yellow t-shirt and here it is okay add another now there's two in in the cart and this is the total add another shirt three in the cart in the total and let's check these products by category views so let's say some fruits add the watermelon and it's updating accordingly okay and if i go to view card here is the correct card overview okay great that's gonna be it for this video see in the next one in this video i'm gonna modify this code so that when we click here add to cart we get that image and then the message and so on okay so let's see in here as soon as i click i want to first of all get that ajax bg div so i'm going to say ajaxdiv let aj is there and that's going to be equal to this and parent parent and find there with the class of hedrick's bidgee okay so i want to get if i click here at the cart i want to get the specific hxb here because each product has its own adw so i said let me right click inspect when i click this a i'm gonna go to parent and parent which is call dash 4 and then find this address bg div ok and then i want to remove that dna class whoops okay and inside of the ajax in the callback that is after i filled the small car div with returned data i'm going to say ajax div find and find that image adox loader image the only one that's in that helix dev and i'm gonna add class of dna to it to hide it okay because as soon as i remove this dna i'm gonna see the atrix loader as well so after the get request is done i want to hide that image so just give it this dna bootstrap class and i'm actually just going to make a copy of that and find the p as well and for the p i'm going to say remove class dna so that i see it and i'm gonna reset the whole thing after two seconds so set timeout and i can have an arrow function in here so i'm gonna say here ajaxdev and first of all i'm just gonna set its opacity to zero with an animation so i'm gonna say animate and pass an object in here so opacity zero and the callback and say this add class dna so this this is the agex div and i also want to fade it to opacity of 1 again in 0.1 seconds so opacity 1 and this find image and remove class dnn and copy that find p and add class dnn again to the p and the reason i'm setting its opacity to 0 here and then back to 1 is because of the animation okay i don't want to just give it a class of dna i wanted to have an animation because that's a better ui experience so anyway let's test this out refresh okay so if i click add now and there it is looking good it's all fast because it happens fast but it happens as it should first there's the ajax image and then the product has been added and it all disappears and resets okay great let me just uh copy this this whole getagex request to products by category like so save that okay that should do it that's gonna be it for this video see in the next one in this video i'm gonna revisit this uh clear cart method and show you a few more useful redirects okay so right now we are saying here return redirect to action index which is the index method in this controller so let's just test it out quickly add something go to clear cart and it goes to the cart page which doesn't really make sense and i'm gonna change that and show you a few other redirects okay so first of all the thing we haven't covered still is redirecting to an action method in a different controller so let's say i wanted to redirect to the pages action method in the pages controller let's just see it the page method actually that is okay so i could say here page for the method and then specify the controller pages so let's see what happens now if i go to all products let's say add to cart clear card here and you can see i'm taking to the home page okay so that's how to redirect to an action method in a different controller but one useful thing to know as well is i'm gonna make a copy of this and just comment it out so you have it as a reference is you can just say here redirect just like so and let's see string url okay so this is literally gonna redirect to the specified url so this takes us to the root basically right so we can with just redirect say just a forward slash for the root save that and let's go to all products again okay so add to cart and if i click now clear cart i'm taking to the root again but in a different way and the third redirect i want to show you is make a copy of this one control kc to comment it out and the third option i want to show you is how to redirect back to the previous request okay so for that i'm gonna have redirect again here but in here for the argument i'm gonna say request headers pass refer in here and tostring okay so now if i go to all products and click yeah to cart here so i am at the all products page i click clear cart and i'm taking back to that same page from which i made the request and if i go to let's say add something here and go to services let's say clear cart same thing okay that's going to be it for this video see in the next one in this video i'm gonna get started with the checkout process and we're gonna check out the paypal so i'm gonna search for that say adding paypal checkout to your third-party shopping cart and here's the link okay so you can go through this read the whole thing i'm just gonna show you briefly what's up so there are two methods method one is passing the aggregate amount to people so the whole thing and meta2 which is right here it's passing individual items to people and that's what we'll do okay so let me just get the form from here so i'm gonna copy that and in the views cart folder i'm gonna add the view which is gonna be a partial view and i'm gonna call it paypal partial okay get rid of everything and paste that form so let's see here what it says for meta2 so first change the cmd input from this to this so value should be underscore card i'm gonna copy that and paste that there let's see what's next now we need to define item specific variables and before that i'm gonna enter my email here okay so to use the paypal sandbox you first need to have a paypal account a regular paypal account and then you can create a sandbox and you can use my sandbox email for this course but you would need to create sellers and buyers as well in your sandbox account and i believe i'm already logged in with my sandbox buyer account so i'm not sure you're gonna see the whole thing that i see but once again you need to have your own regular paypal account in order to use the paypal sandbox so anyway my sambox email is this slash facilitator and gmail.com okay so anyway back to here to pass item specific variables you have the names here and this x is the count okay so as it says here the x values must increment by one continuously and so on so once again you can go through all of this i'm just going to use the necessary ones to get a list of all the products that i have in the cart so in the form i'm gonna get rid of the amount and item name okay and up here i'm gonna initialized a count variable so add and curly braces and i'm gonna say and count is equal to one and increment this account for each product so how do i get the products in this partial view we use the partial view before let me just find it it's the notifications one actually in the admin area so let's see it this one right here and this partial view used its own data so nothing was passed to it but when you call a partial view you can pass data to it okay and i'm gonna pass to this paypal partial the cart items when i call it so i'm gonna loop through those cart items in here i'm gonna save for each so for each item in model and once again the model will be the cart items so let's see from here what they need i'm gonna use this item name and the amount and also quantity so that quantity isn't listed here but it exists so anyway i'm gonna have a hidden input here let me copy from up there just bring this back a bit okay so name is item name item underscore name underscore and x so this right here and the x is the count variable so it's going to be 1 in this case and the value is going to be item and product name with the capital p and i'm gonna duplicate this twice so next is the amount so this right here so copy that and paste it here amount underscore and count whatever the count is and the value is going to be item and price and finally the quantity so once again that quantity isn't listed here for some reason but i know it exists so quantity underscore count and value is going to be item quantity and now in the index view i'm gonna [Music] inject that partial view so after this cells i'm gonna say partial and the name and because this isn't in the default location which is the shared folder like we have it uh here in the admin areas i need to specify the full path so it's going to be tilde and views slash cart slash underscore paypal partial cshtml and i need to pass the data to this partial view so i'm going to say 4 and cart items and i just realized i forgot to increment this count in here so i'm just gonna say here count plus plus okay so hopefully that should do it let's see if i go to all products and that to cart this and this and go to view cart so here's the paypal button and if i inspect it here are the cart items okay so value 399 for the amount item name is yellow shirt and here's the quantity as well and then the second item so it's all good and let's say if i add another here so add another yellow shirt so yellow shirt and quantity value is two okay so it's all good and if i click this paypal button i have a bit of a problem and that problem is something i didn't see in the documentation now but should be in the form so i'm just gonna add it and that is after this underscore card let me actually just duplicate it i'm gonna have another hidden with the name of upload and the value is gonna be one okay so now it should work let's check not sure why that's not in the documentation but i know that's needed as well okay let's just add a yellow shirt and a white shirt go to view card click people and let me see here okay this is supposed to be the sandbox paypal sandbox not the regular paypal account okay this is supposed to link to the sandbox paypal not regular people so i'm just gonna say sandbox here save that and let's try again just refresh this page okay again add a shirt and a white shirt and go to view cart and paypal again okay so here it is here's the total and if i click here i get the names and basically all the details if there's more than one it's going to show up as well and so on so it's all here and once again i want to mention that you might not be able to see this because as you can see this test buyer i'm logged in as a test buyer which you can create only in the sandbox account so once again you should have that paypal sandbox account if you want to see all this okay that's gonna be it for this video see you in the next one in this video i'm going to modify this card overview page so that when we click checkout a message pops up here saying that we are being redirected to paypal and also to submit the paypal form when this checkout is clicked okay so let's get to it so in this index view so cart index i'm gonna have this table in a div and i'm gonna give it a class of card wrapper like so and let me just end that here like so and in here i'm gonna have a div with the class of card bg and in here nh3 with the class of text center and this is going to say redirecting you to paypal and i'm going to have that ajax loader in here as well so let me just grab it and drop it here like so okay so if i refresh and add the product and go to cart so here it is now i'm to go to site css control comma site css and just tell it a bit so i'm going to say first of all that that card wrapper div is position absolute actually relative and div card bg and let me just copy from this ajax bg so the same thing and div card bg and h3 and let me copy from this image here so position absolute top 50 percent and left fifty percent as well and translate i'm gonna get rid of the x so minus fifty percent and minus fifty percent so that's gonna center it both horizontally and vertically and the image as well so make a copy of this position absolute top can be sixty percent and just change this to image left fifty percent and translate i'm gonna say minus fifty and minus sixty percent okay that should do it let's see ctrl shift r and looking good let's just let's see here i'm gonna remove minus from here so just 60 and that looks good okay so just 60 here i mean it doesn't really make a difference i just want it to look decent so anyway that's uh good enough and i want to get rid of this paypal button here so for that i'm gonna go to the form paypal form and give it the class of paypal form okay and inside css i'm going to say that form with the class of papal form he has a position absolute and left minus 3 000 pixels let's say just to get out of the way so refresh again and let me add something so a shirt a shirt and a shirt view cart okay there's no people and i'm gonna give to this card wrapper div a class of dna to begin with because i don't want to say it when i go to the cart overview i want to see it when i click checkout okay so anyway in the index view here after the partial and let me just copy from [Music] products index for example this section scripts thingy paste it here and i'm going to remove the body from this add to cart except the e prevent default so this is going to be a with the class of checkout and let's give that class to this a here so check out and i'm also gonna say get that div card bg and remove class d none and before i submit the form i also want to clear the session so i'm going to make an 8x call here to cart clear okay so i'm going to say get and let me just space this out a bit so get slash car slash clear and just pass an empty object and have a call back here and in the callback i'm gonna submit the form so form paypal form and submit okay and now i need to go to that clear method in card controller and check if this action method is invoked normally or from ajax okay so i'm gonna copy from add here so this if it's an xml http request and paste that here if it's not that is so if it's not i'm going to return this redirect otherwise i'm going to return ok so ok 200 response okay save that and uh let's see what happens i'm gonna go to all products and ctrl shift r just to clear the cache and get that new css so add this and this and this and one more white shirt go to view cart and there's nothing because i see here i added the nunn to cart wrapper i wanted to add that to car bg actually okay so just get rid of that and add it to this one save that refresh and once again add this and this and this and one more white shirt go to view cart so here's the whole shebang and if you click checkout here it is the message and you can see it's working here okay so here it is here's the total and if i click here you can see that for example for the white t-shirt i can click more because there's two of them so that's listed here quantity two item prices 399 and so on so it's all good and if i go back to here i can see that the card is empty so the session has been cleared okay great that's going to be it for this video see in the next one in this video i'm gonna get started with identity okay so identity in asp is responsible for managing users so registering logging in and out having roles and so on okay so anyway to get started i need to create a class to represent the user so i'm going to right click the modules folder and go to add class and call this class app user okay and this class is gonna extend identity user like so so that comes from asp.net core identity and just like so we're gonna have all the necessary tables and so on so for the user specifically the user's table is gonna have email username and so on so all the necessary stuff but you can also add your own columns in there and i'm gonna do that now so here i'm gonna say prop double tab string and call this property occupation so on top of all the default ones the users table is going to have this occupation column as well and you'll see what i mean in a minute but anyway now i need to modify the db context class as well so i'm going to go to infrastructure and see my shopping cart context so now here the change i need to make is instead of extending from db context i'm going to extend from identity db context okay and i'm also going to need to install this ef core identity ef core package so find and install latest version and also here i need to specify that user class so app user in this case save that and that's all that's needed okay so before i do the migration i just want to mention that what we have so far regarding the database operations still works so everything is the same as before this is basically the same as the just extending db context like we had before but now we also have this identity support okay so anyway on to the migration i'm going to open package manager console here and i'm going to say add dash migration and i'm going to call this one identity create okay and now i'm going to say update database okay let's see if i open the cms topic or context tables here so right click refresh and now as you can see i get a bunch of tables here all things to identity and of concern to us are the asp.net users user roles sp netrols those three we're going to be using okay and let me just open this asp.net users table so right click view data actually i wanted to say view designer okay so there's a bunch of columns here so username email password and so on and there's also this occupation which we added okay so anyway that's going to be it for this video see in the next one in this video i'm going to create a new user class so i already have this app user but this is used for the table creation and so on and now i'm going to create an actual user class that's going to hold the user data that i want okay so i'm going to right click the models and go to add class and call this class simply user and in here i'm going to have a property string username so capital u and n and string email and string password and that's it for the properties now i'm gonna have an empty constructor just in case i need it because i'm gonna have a constructor with parameters as well okay so to whoops ctor so to this constructor i'm gonna pass app user so app user app user and here i'm going to say that username is equal to app user oops and username and email is equal to app user email and password is equal to app user and password hash okay looking good that's gonna be it for this video see in the next one in this video i'm gonna enable the use of identity in the startup cs file create the account controller and also introduce you to the authorize attribute ok so let's get started first of all to actually be able to use identity you need to specify that in the startup cs file so i'm going to go there and add a service here in configure services method so after this adb context service i'm gonna say services add identity okay and here i'm gonna say app user and also identity role so that rows are enabled as well and add identity framework stores and pass here the cms shopping cart context and finally say add default token providers this should be like so okay so let's see here import identity and that's good now okay so that's the whole thing and let me just bring this down like so so it's a bit easier to see oops okay and in the configure method i'm gonna also say here after use authorization i'm gonna say app use authentication as well okay great that should do it for the startup file and now i'm gonna create the account controller and that's gonna serve for registering logging in and editing users so anyway in the controllers folder right click add controller empty and i'm gonna call it account here it is so for now i'm just gonna return a string here for the index method just say hello and let's test this out i'm gonna go to slash account okay here it is and now i want to introduce you to the author as attribute so i can specify that attribute for the whole class okay say author is here like so and now you have to be logged in in order to access any method within this class so if i refresh you can see up here that it tried to access accounts login method or page and there's this return url as well okay so because we're not logged in it tried to send us to account login which means it's working so this authorized attribute can either be like so on class level which means that it affects every method within the class or it can be per method so i can for example get rid of it there and have it just for the index method okay but i'm gonna have it for the whole class and that's gonna be it for this video see in the next one in this video i'm gonna do the get register method and view okay so i'm not gonna have this index method here i'm gonna change it to register and this fat arrow here and this is gonna return the view and get rid of the body here and i'm gonna say here i action result okay and just have a comment here as well so get slash account slash register and now i'm going to go to the user model here and add validation and let me open for example page as well and just copy some from here so this one here requirement length i'm gonna have that for the username and just import data annotations and copy that for email as well so for email i'm gonna have required and i'm gonna say email address and i'm gonna copy this for the password as well so i want required i want mean length which is going to be let's say 4 but i also want to specify that this is a password data type okay so here for example i'm going to say data type and in parenthesis data type password okay save that looking good so in account to create the view right click the method add view so register template is going to be create and model class is going to be user let's click yet here it is so i'm going gonna get rid of this namespace here and just paste this out a little like so and i'm gonna change this create to register and let's see get rid of dh4 and hr and change this to 10 like so and let's see down here what we have so back to list i'm gonna get rid of that and scripts with validation okay so let's see this i'm gonna go to account slash register and as you can see again it wants to take me to slash account login why because i'm saying here authorize for the whole class so again when you have this authorized on the whole class it's applied to every method in the class but you can get around it for particular methods by annotating this with allow anonymous okay so now anyone can access this specific method but any other method would still be accessible only to authorized users so if i go to account slash register again let's see now and here it is now i can access it okay this is a password input right click and inspect so input and type password okay and we have the username and the email which is of type email and for this username i'm just gonna let's see here just say username here like so okay and try to register and i get the error messages so it's all good that's gonna be it for this video see in the next one in this video i'm gonna do the post register method and before that i just want to make a small modification here so now if i click register here it says username with the capital n so let's just make that lowercase n so instead of here i'm going to get rid of that username there and in the user class i'm gonna let's see here i'm gonna say display and set a name here okay to username like so so it's not a big deal but why not and now if i refresh it says username here like so and if i click register is the same here okay so anyway on to the post method i'm gonna make a copy of this get here so this is gonna be post account register and i'm still gonna have this allow anonymous here and just have curly braces here like so but here i'm also going to say http post and validate and forgery token and this method is going to be a synchronous so a sync task i action result okay and i'm passing that user model here right so user user okay looking good so first of all as always check if model state is valid so if model state is valid in that case i'm going to create a new app user based on the user data okay so i'm going to say app user app user and that's going to be equal to new app user and here i'm gonna say username is equal to user username and email is equal to user email okay so now here i want to create the user but i'm not going to be using that db context we used before identity uses its own things okay so i don't even have a dependency here and i'm going to add a dependency now but that's not going to be the db context it's going to be user manager okay so i'm going to say here private and read only and the user manager and specify app user here and i'm going to call that use manage user manager that is and add it to the constructor so ctor and i'm just gonna copy this paste it here and say here this user manager is equal to user manager like so okay looking good so now here i'm going to say identity result result is going to be equal to so this identity result let's see it represents the result of an identity operation okay so now here i'm gonna say await and user manager create async and here i need to specify the app user and the password so app user and user password okay so i'm gonna say now if result succeeded in that case i'm gonna return a redirect to action which is gonna be a login which doesn't exist yet but it will soon enough else i'm gonna loop through the errors so i'm gonna say for each identity error error in result errors okay and model state add the model error empty string and error description and finally i'm gonna return the view with the user in case the model state is not valid or there are errors here okay looking good so save that and now if i just refresh here first of all okay so i'm going to say here drawn and email john at gmail.com and password pass and register user master parameter list constructor i thought it did okay public let's see now that was a bit of an oversight on my part but anyway that should do it let's try again so pass register and great it works okay so i'm getting these errors here which is a good thing it means this works but by default all these validations here must be respected and they don't come from the user where is it here the password here okay that's built in into asp identity and that can be changed and we're gonna do that in the next video okay see you then in this video i'm gonna deal with this validation rules here that we got in the last video so i'm continuing right where i left off in the last video so as i said then that's not something you added here in the model okay to deal with that i'm gonna go to the startup cs file actually and in here i'm gonna say options and fat arrow curly braces and i can deal with that in here so i'm gonna say options password and then let's say here i can say required length okay which is four and let's see here it says six but i want it to be four so now it's four and let me just indent this like so okay so what else do we have here at least one non-alphanumeric so i'm gonna say options and by the way these are all good things to have for passwords okay i just want to override this because i don't want to have to write complex passwords for this project so you might want to keep this for your own products is my point but for this one i'm gonna get rid of it so let's see here options password and required non-alphanumeric and let me see here okay there's this bug in visual studio preview this loading intellisense sometimes gets stuck it hangs so i'm just gonna get rid of that now save this and i'm just gonna reopen visual studio and get back to the video okay so see you in a second okay here i am so options and password and required non-alphanumeric here it is i'm gonna set that to false okay and i'm just gonna duplicate this line three more times so i'm also gonna say here require lowercase false and require uppercase false and require digit false okay so there's more here so you can go through this on your own but this is gonna do it for this validation errors here so anyway i need to restart the project again okay so let's try again drawn and john gmail join gmail.com and password pass and register and great it redirected me to login which is what it does in case of success right here okay and let me just check the table so aspinat users right click view data and here done okay great that's going to be it for this video see in the next one in this video i'm going to create the login class so in the models folder i'm going to add a new class and call it login and this is going to be similar to user so i'm going to get all of this from user and paste it here but i'm not gonna have the username because we're gonna be login with email and password okay so i want here let me import data annotations i want for the email to be required and email address password as well same as it was and i'm gonna get rid of these constructors here and have another property here string return url so if you remember there's that return url query string when the user is redirected to login if they try to access a page that needs authorization so i'm just going to cache that in here in case it's there okay looking good that's going to be it for this video see in the next one in this video i'm going to do the get login method and view so i'm just gonna copy from here and paste that here but i'm gonna have curly braces here and just change this to login and this as well whoops okay so in here i want to get that return url from the query string if it's there so i'm gonna say string return url okay and i'm gonna use that login class here so login login new login and return url equal to return url and finally return the view with the model okay looking good so to create the view right click inside add view so your viewer name login template create model class login that should do it okay here it is so i'll just get rid of this namespace here and this h4 and hr and this is going to be 10 and let's see here i don't want this return url div let me just paste this out a bit and change this to log in and get rid of this div right here back to list save that looking good and in this video as well i'm just going to add the register and login links to main menu here but to the right okay so they are not part of the pages anyway in the main layout let's see here it is so here i'm gonna i'm gonna make a copy of this actually so just ctrl d and that's going to be up here get rid of the way there and to this i'm going to add justify content end okay so for the links i'm gonna say li here with class of nav dash item and have an a here with class of btn and btn their success okay and get rid of this href i'm gonna say here asp controller is account and asp action login and i'm gonna say login here so save that and copy this lay ctrl d action is gonna be register and register here as well and i'm just going to add another class to delete ml-1 so margin left one and let's see refresh okay here it is looking good i'm just gonna change the register button to let's say where is it here to primary just so it's of a different color and refresh again okay great that's gonna be it for this video see you in the next one in this video i'm gonna do the post login method and before that i just need to make a couple of changes so first of all in the startup cs file let's see here there should be first use authentication and then use authorization okay so the order is important and secondly i realized that this uh here actually i'm passing this return url to the property here of login but in the view i don't have it in the form so i'm just gonna say here input hidden and asp4 return actually return url save that okay so on to the post login i'm gonna copy this post register and paste it here so this is gonna be login and this is all good and this is gonna be login as well and here login login like so and i'm gonna get rid of everything inside this is valid and finally return view with login model okay so before i get started in here i need to add another dependency so up here i'm gonna make a copy of this and now i'm gonna say sign in manager okay so that's responsible for signing in not the user manager so change this to sign in manager as well and copy this whole thing paste it here make a copy of this so sign in manager and sign in manager like so okay looking good so back in the method if the model state is valid first of all i need to get that user so app user app user is going to be equal to await and user manager and find by email async login email here and now check if the user exists so if app user is not null in that case now instead of i used identity result here but here i'm gonna use sign in result okay and for that i need to use this fully qualified name like so result and this is going to be equal to await and sign in manager now password sign in async and there are two overloads for this method so the first one is this one right here now string username password is persistent and lockout on failure and the second one is the same thing but the app user is passed here not the username and that's the one i'm going to use okay so i'm going to say app user here and login password and false and false okay so now i'm going to say if results succeeded and i'm going to return a redirect so either to that return url if it exists so login return url and if it doesn't i'm going to return to the home page and if the user is null so if the user doesn't exist i'm going to add the model error so model state add a model error and i'm going to say login failed wrong credentials okay save that hopefully that should do it and i'm also gonna go to the product controller and just have this whole class authorized so that you can only access it if you're logged in i mean this wouldn't make much sense i guess in a real application a real world application but for us it's gonna do because we can easily test stuff out like this and have some part here on the front end that's locked out basically okay so anyway now if i go to all products let's say and i can't access it so i'm taken to the login page and here's the return url so now if i say john at gmail com and pass login and great now i can access it which means i'm logged in and t-shirts fruits all products it's all good and finally i want to show you if directly can inspect and go to let's see application here and cookies and the current url so this localhost for us and you can see here let me just expand this there's this asp.net core identity application cookie so that's because we're logged in okay so anyway that's gonna be it for this video see in the next one in this video i'm gonna do the logout method so i'm gonna copy this get login here and paste it here and just get rid of everything in here and get rid of this allow anonymous as well because you have to be logged in in order to log out and change this to logout as well and method name and get rid of this and this is gonna be async so public async and task okay so to log out it's actually really easy i'm gonna say await and sign in manager sign out async and that's it and after that i'm going to return to home so redirect and forward slash and that's it okay so let's test this out let me refresh here to see if i'm still logged in and i am so if you're not logged in log in and i'm gonna go to account slash logout and i should be logged out if i try to access products i can't okay great and also i want to add the logout link in the main layout so here okay so if i'm logged in i want to say log out and if i'm not logged in i want to see these two so to do that i'm going to have an f here so i want to check if the user is authenticated so i'm going to say user and question mark just to check if it's null and identity question mark and is authenticated and if not i'm gonna set this to false okay so if the user is authenticated then i'm gonna have the logout link so i'm gonna copy this one paste it here and this is gonna say log out and i'm also gonna add the username in here so i'm gonna say hi and user identity name and a comma okay so hi user logout and this is gonna point to logout and i'm gonna change this to danger and have an else here so if the user is not authenticated i'm gonna have these two okay so let's see refresh let me login so john and gmail.com pass okay and here i see how i draw logout and i can access products and if i click here i'm taken to the home page and i can see now log in and register here and if i try to access products i can't okay great that's gonna be it for this video see in the next one in this video i'm gonna do the get edit method and view okay so i'm just gonna copy this logout and this is gonna be account slash edit and add it here okay so when here get rid of everything and i need to get the user so app user app user and that's going to be equal to await and user manager and find by name async and the name is user identity name okay so now i'm gonna say user user and that's gonna be equal to new user and pass app user here and finally return the view with the user okay looking good and by the way this is where that constructor comes in with the parameter so if i control click user right here okay that's why we have that there i mean you don't have to have it you can just add that stuff in here but i think this is cleaner so anyway to create the view right click and add view edit template is gonna be edit model class is gonna be user and that's it create or add okay so here get rid of the namespace and the title edit account let's say and here as well edit account and get rid of the h4 in the hr and i don't want to be able to update the username i'm just gonna pass the username in a hidden input so input hidden and asp4 username okay and email i do want and the password i want as well and let's say add it here and get rid of this back to less div save that looking good let's also add that edit link or my account link in the main menu so i'm gonna go to layout again and make a copy of this list so ctrl d and this is gonna point to edit and i'm gonna say primary here and this is gonna say my account save that okay so let's see refresh here it is so if i log in as john and pass okay hi drone logout here in my account let me just add to this lee ml-1 refresh okay so if i go to my account here it is i can modify the email and the password so so far so good that's gonna be it for this video see in the next one in this video i'm gonna do the post edit method and i'm gonna make a change here i'm not gonna be using this user this user actually i'm gonna make a new model because as it is now here for the update we need to update both email and password okay because the user control comma let's see the user here specifies that the password is required okay so i'm just going to create a new model so i'm going to just copy this user actually and rename it to user edit like so okay so user added here and i don't need the username email i do need and pass what i do need but it's not required okay and i'm gonna leave this default constructor here just in case and this one is gonna be same as before for the user but without the username okay and let's see here for the user i'm gonna get rid of this constructor and get rid of this one as well actually and let's just space this out a bit just so it's a bit easier on the eyes okay so back in account controller i'm gonna say here user edit user and the new user edit like so okay so this should give us the same thing now except that the view expects users so user edit and i'm not passing the username here okay so let's try again okay here it is looking good so anyway on to the post so here we want to be able to update the email and the password and the password should be hashed so i'm gonna need a new dependency up here i'm gonna say private and i password hasher and pass app user here for the type and call this password hasher okay and copy this and paste it there and say this password hasher is equal to password here sure like so and i'm just going to bring this down so it's easier to see like so okay so in the post method now i'm gonna copy this post login actually paste that there so this is gonna be edit and edit and i'm passing user edit here but i'm gonna call it user okay and i'm gonna get rid of everything from here except for this one actually i'm gonna cut and paste that line that finds the user and get rid of everything else and return the view here okay so here instead of find by email i'm gonna say find by name async and the name i'm gonna get from user identity and name okay so now in here i'm gonna say app user email and that's gonna be equal to user email and the password i want to update if there is a new password otherwise they don't okay so i'm going to say if app user actually if user password is not null in that case i'm gonna update it otherwise i'm not so app user password hash and that's gonna be equal now to password hasher hash password and app user and user password okay so now i'm gonna have that identity result result and that's gonna be equal to await user manager and update async and pass the user here and if result succeeded let's just return a redirect to home for now just to see if this works as expected otherwise return the view if the model is not valid okay so let's test it so here if i say drone2 and edit i'm taking to the home page so hopefully it worked let's see let's log out login so drone2 at gmail com and pass okay i'm logged in my account and let me change the password as well now to let's say pass to edit it seems i've updated the password let's log out login again so john 2 gmail and pass2 for the password and i'm in okay seems to be working fine actually i wanted to click my account there just to go back to john and pass so my account and this is gonna be john the gmail and password pass edit once again just to make sure login john gmail and pass okay great it's working fine and actually let's add a success message here for the update of the user so instead of this return redirect now i'm gonna have tem data success and that's going to be equal to let's say here your information has been updated or edited let's say edited okay and then return the view so for this to work i need to get that notification partial from admin shared here admin viewer shared so i'm gonna copy that and paste it in shared here okay so paste that here it is and i need to include it in the layout file so where is it here in main i'm gonna say partial and the name is gonna be underscore notification partial and close that okay so let's see if this works now login so john gmail and pass okay i'm in and go to edit i'm just going to add the email now edit and here it is your information has been edited and i'm back to this page okay great let me just added this back to john okay great that's gonna be it for this video see the next one in this video i'm gonna go back to the admin area and make a list of all the users so that the admin can see all the users okay so in areas admin and controllers i'm going to right click and go to add controller and i'm gonna call it users controller okay so i'm gonna just say here area admin and i'm gonna open the account controls to control comma and account controller just so i can copy and paste the dependency and for this one i just need the user manager so get rid of this and this and that and change the constructor name and import spirit core identity and models okay good so for the index view i just want to return all the users so i'm going to say user manager and users like so okay so now to create the view right click add view view name index template is going to be a list model class i'm going to need to change this but i'm going to say user anyway just to get some html there okay so add okay so here it is and up here i'm gonna change this innumerable user to app user okay and change the title here to users and this h1 as well to users get rid of create new and let's see okay so i want to have the id and the username and the email and the actions here so in the 4h i'm going to say item whoops id here and this is going to be item and username and item email and i'm actually not gonna have these actions here because they don't want to add it and so on the users from the admin area because each user can do that for themselves so i'm gonna get rid of that actually and let's check this out so that's gonna be slash admin slash users okay so here it is the id and by default the ids for users are actually strings not integers for some reason but anyway here they are so we only have drawn now and let's create a few more because we'll need them so i'm just going to go to the home page and register and say bob here and bob at gmail dot com password pass okay and the admin as well so admin admin add gmail pass and let's say mary and mary gmail.com and pass and i think that should do it and finally i'm gonna go to the main layout view here for the admin and just add that link so let's see here it is okay so copy that lastly and controller is users and action is index and this should say users so let's see if i go to the admin area admin pages let's say so here are the users and if i click it here they are okay great that's gonna be it for this video see in the next one in this video i'm gonna get started with roles okay so roles enable you to allow access to specific areas of the website only for certain authorized users with certain rules so anyway in this series of videos i'm gonna create a system in the admin area that can create rows and add them to users okay so to get started i'm gonna right click controllers in the admin folder admin area that is so add controller empty and call it roles okay so i'm gonna say here first area is admin like so and now i'm gonna add the dependencies so i'm gonna say private read only and role manager now okay so that's responsible for dealing with roles and in here i'm going to pass identity role and call this role manager and i'm also going to need the user manager in some methods so i'm just going to add a dependency now ctrl d to copy this one and this is gonna be user manager and pass app user here and this is gonna say user manager okay create the constructor ctor double tab and copy this and paste it here and this as well so this role manager is going to be equal to role manager and this user manager is going to be equal to user manager okay that's going to be it for this video see in the next one in this video i'm gonna do the index view and the method so i'm just gonna get rid of this body here and have a fat arrow here and say view so return the view and the role manager roles okay save that and add the view right click add view so index is the view name the template is going to be empty and use the layout paycheck okay so add that okay here it is and i'm going to get rid of everything in here and for this view i'm going to copy from pages index let's say so views pages index and just get the whole thing and paste it here and modify it okay so first of all for the model this is going to be identity role a numerable identity role okay so i'm just going to get that from here the namespace microsoft has pnet core identity and paste it here and identity role here like so the title is going to be rows and this h1 as well create new is fine and for the table i'm going to get rid of sorting and this id okay so here i'll get rid of all these ths and this class home so i'm going to have the idea of the rule the role itself i'm gonna have the users that are assigned this specific role whatever it is and also some actions so in the 4h here let's see i'm going to get rid of this id and class here get rid of this as well just have it in a single line this titties so i'm actually just going to say row here let's say so roll id and copy that this is going to be roll name copy that and the users i'm going to have in here but for the users i'm just going to say users for this role for now so for this td right here i'm going to create a custom tag helper that's gonna get me the users based on the role but i'm gonna do that later on okay and in here i'm gonna have edit so row id here and delete so i'm going to get rid of this details one and this if here and i'm going to say this is roll id and finally get rid of this section scripts here i don't need that save that and also i'm going to add this roles menu item to the layout so and here this is going to be rows action index and this is going to say roles okay save that and let's see what we have go to the admin area here it is so if i click roles and here's the view okay so far so good since we don't really have any rules okay that's going gonna be it for this video see in the next one in this video i'm gonna do the get create method and view so i'm gonna make a copy of this index one and let me also just uh make some comments here so this is gonna be get slash admin slash roles and whoops copy that control c control v to paste this is going to be slash rows slash create okay so rename this to create and just return the view without any model so to create the viewer right click add view viewing create empty template and use a layout page so add that okay so again i'm gonna get rid of everything and i'm gonna copy from categories let's say categories create since there's less html here than in the pages for example and we don't need much paste that so for the model this time i'll just say string okay so just use a string and the title is going to be create a row here as well for the h1 create row okay get rid of this h4 and hr and actually while i'm here let me get rid of that in here as well i don't need that for the category create either but anyway i'm going to close create category view here so back to this one for the label here i'm gonna say roll name and have an input but it's not gonna be this for input i'm just gonna create it myself so i'll get rid of sp4 and say that the type is text and the name is gonna be name and i'll get rid of the validation here and this sp4 as well in the label get rid of that and the rest is fine okay so save that and let's go to create new here and here it is looking good okay that's gonna be it for this video see in the next one in this video i'm gonna do the post create method so i'm gonna copy this get one let's say ctrl d paste it here and have curly braces here so this is gonna say post and http post and validate the token and the forgery token and the method is going to be async so async task i action result like so okay so here in the view we're saying that the model is a string which means we want to pass just a string here okay so i'm gonna validate it here as well that's possible too so i'm gonna have square brackets here and say mean length two and required okay and string name so here the name is name of the input and of course you can make a model for this here the role name i just wanted to show you that you don't have to okay so anyway i'm gonna do it like this so again if model state is valid as usual i'm gonna have identity result result and that's gonna be equal to await and role manager create async and here i need to pass that identity role so i'm going to say new identity role and the name okay so if result succeeded i'm gonna return a redirect to action index else i'm gonna loop through the errors so for each identity error error in result errors model state add model error and error description like so get rid of this curly braces here okay and if the model state is not valid i'm going to say here model state add model error and minimum length is 2 and return the view with the name save that okay and let's test this out now so if i refresh here and say create and i get here minimum length is 2. okay that's not going to work so if i say let's say now admin and create and it seems to have been created okay here it is the rows index view let me also add the success message actually so i'm just gonna have braces here now curly braces and say here temp data success and that's gonna be equal to the role has been created okay and return to index else and this so let's create another role let's actually try to create the same admin role first of all okay here it is so admin create and yeah i'm not actually going to pass the name here because this becomes the name of the view because it's a string it's not a model class so anyway just get rid of that and go back to create so admin and create and it says here role at name admin is already taken so let's see this here is kicking in okay okay so great and let me add another row here so let's say editor and create and the role has been created so we get the success message so it's all good going to be it for this video see in the next one in this video i'm going to create the role edit model which i'm going to use for editing roles so in the models folder let's see here i click and add class and call this role edit okay so first i'm gonna have an identity role called role and i'm gonna have innumerable app user for members so members of the role copy that and none members as well and the string row name and the string add ids and that's gonna be an array and the string delete ids okay that's gonna be it for this video see in the next one in this video i'm gonna do the get edit method so let's see here in rows when i go to edit it's slash edit slash sum id which is a string okay so i'm gonna copy this post one ctrl d and this is gonna be get admin rows edit and some id get rid of the post and this validate and this is gonna be called edit so here i'm gonna pass that string id okay get rid of this and get rid of everything in here as well okay so first i need to get the roll so i'm gonna say identity role row is going to be equal to await role manager and find by id async and pass the id in here and now i want to make lists for members and non-members so i'm going to say list app user members and that's going to be equal to a new list of app users and copy that and the same thing here just none members okay so now i'm gonna loop through the users and add them either to members or the members list so i'm gonna say for each app user user in user manager and users and the viral list and that's going to be equal to await user manager is in role async okay so this method checks for the role so user and role name if it is the list is going to be members otherwise otherwise it's going to be non-members and then say list add user okay and finally return the view so return view whoops and this is going to be a new role edit so roll is going to be equal to row and members to members and the non-members to non-members okay looking good and that's actually gonna be it for this video and i'm gonna do the view in the next video because it's a bit more involved okay see you then in this video i'm gonna do the edit view so right click inside the method add view view name edit template is gonna be edit and model class will be row edit and use a little paycheck add okay so in here i'm going to get rid of the namespace here and the title is going to say edit roles and this h1 edit roles get rid of dh4 and the hr and let's see now in here this validation summary i don't really need but i'm just going to leave it there okay so let's see now i want to have two devs in this form one for adding users two roles and the other to the role and the other for removing users from the role okay so two devs with two tables a table in each so i'm gonna get rid of this dev form group and i'm gonna have a hidden input here first for the role name because i need to pass that to the post method so asp4 role name and actually this isn't going to be asp4 i'm going to say name is role name because i need to get it let's see the value i need to get it through model and then roll and then name okay so have it like so and now i'm going to have a row with call 6 and another div with the colder 6. so this one here it's going to have an h2 and it's going to say add users to and i'm going to have a span with the class of badge and badge primary and say model role name here and row okay and then i'm gonna have a table with a class of table and table bordered and in here first i want to check if there are any none members for this row so i'm gonna say f model non-members account is zero then i'm gonna have a tr with the td and say all users are members okay else for each so for each app user user in model non-members and then have a tr in here and the td so user and username and another td with the checkbox so input checkbox value is going to be user id and the name is going to be add ids i don't need the id okay so this add id is here is actually in row edit control comma row edit it's this one right here okay so a string of add ids that's why this is a checkbox because we are going to have an array here of ad ids so you can add multiple users to a role at a time okay and now to remove and it's kind of the same thing so i'm gonna copy actually the table and the h2 copy the whole thing paste it here and this is gonna say remove users from the role whatever it is so now if model members account is zero in that case i'm going to say no users are members else for each user in members i'm gonna have the username and this is gonna be delete ids okay so this right here an array of strings called delete ids okay looking good so now let's see if i go to edit admin okay it seems to be working it just looks like crap so let's see what's up here and this is supposed to be 10. okay let's see now okay great so we don't have any users for any roles right so for admin it says no users are members which is correct and add users to admin roles so here's a list of users that you can add to the row which are all the available users and back to list if i go to editor role edit and the same thing no users are members and here's a list of all the users that can be added okay looking good that's gonna be it for this video see in the next one in this video i'm gonna do the post edit method so i'm gonna copy this get one and say here post and the comment is fine so let's see add the http post attribute here and validate anti-forgery token okay so let's say here i'm gonna pass the model so role edit role edit and i'm gonna get rid of everything in here so first i'm gonna declare identity result okay identity result result just like so because i want to both edit and delete users from the role so anyway now i'm going to loop through ad ids that add ideas string right so this one here and this one here so for each string user id whoops and this is supposed to be capital i so for each string user id in role edit add ids and if that's now i'm gonna create a new array so new string array okay so we are either gonna have an array of ids or an empty array in any case i'm going to say app user user and that's going to be equal to await and user manager find by id async and user id and result is going to be await user manager add to role async and pass the user here and the role name so role edit and row name okay and i'm gonna copy this for delete ids so again for each string user id in row edit but delete ids or an empty array again i need to find the user but then i need to say remove user remove from roll async that is okay so don't get confused by this empty array here and here if it's empty then nothing is going to happen for example for this empty array nothing is going to happen here okay and here as well that's why we have these empty arrays here so if there are any ad ids it's going to add them or it's not gonna do anything and same for delete ids if there are any it's gonna remove them or is just not gonna do anything so it's all good and finally i'm gonna return to the previous request let's return this time so we use that as well so return redirect and request headers refer and tostring save that tokyo looking good so let's see if this actually works go to roles and let's say admin edit so i want to add admin to admin and let's say bob as well save and there we have it almond and bob are in users in the admin role that is so i can now remove them and back to list if i go to edit editor let's say mary can be the editor so save that and here's mary the editor i'm back to list admin and i want to remove bob from admin i just want to have admin for the admin row save and great okay let's also go to the table and see what we have there okay so if i go to roles view data here here are the ids and the names okay so this is the id and this is the name and so on and let's see also user roles here so view data and here it is the user id and role id okay so great that's gonna be it for this video see in the next one in this video i'm gonna create a custom tag helper to display the users here for specific roles okay so first of all i'm gonna go to rows index and here for this td i'm gonna say user dash role so that's gonna be the custom tag helper and i'm gonna give it a value of role id okay so now on to the tag helper i'm gonna go to infrastructure right click and add class and call this roles tag helper okay so is going to extend tag helper and i needed those row manager and user manager dependencies so i'm just going to copy from the rows controller here paste that in here and change the constructor name and import what's needed so identity and models okay so when creating custom tag helpers you'll get the dependencies via constructor same as with controllers and now i'm going to have a property which is going to be a string called role id but i want to target this user dash role attribute so i'm going to say here in square brackets html attribute name and specified okay so that's user dash row and also because i want to target this td so this isn't a custom element like uh let me see in the pertination tag helper okay here a custom element was created by donation but in here we actually want to target a valid html element this td which is a regular html element so because i want to target that td i'm gonna say here on top of the class html target element so which html element to target and that's gonna be the td and i can specify the attributes as well which is role dash user a user dash role that is user dash row okay so does the difference between this one and the pagination one this one creates a custom element and our one targets an actual html element okay and also because it's called user dash role in here the attribute that's why i'm specifying the attribute name here because i call the property role id okay so now same as in the pagination one i need this process method just in our case it's gonna be async so it's either process or process async okay so i'm going to say public override async task and process async and we need the tag helper context context and the output so tag helper output output okay and this output is what outputs the actual string at the end that's returned here so let's see in this pagination tag helper this guy he had this method which he called here in the end but we're gonna do our thing in this actual process async method we're gonna do everything in here the logic okay so first of all i'm going to have a list of names i'm going to say list string names and that's going to be equal to a new list like so and now i want to get the role so i'm going to say identity role role and that's going to be equal to await role manager and find by id async and pass that role id in here okay so this property right here which comes from here and i'm gonna say if roll is not now just in case even though it can't really be now because it's in a list here but anyway let's just have it there so anyway in here i'm to have for each and var user in user manager users so again a loop through all the users and see if there are any in this role so here i'm going to say if user isn't now and await user manager is in role async user and role name in that case i'm gonna add to the names list so names add user and i just want the username okay and now i need to output this so down here i'm gonna say output content and set content and i'm gonna check if names count is zero in that case i'm gonna say no users otherwise i'm gonna say string and join and have a common space here and the names save that and let's see if this works so if i refresh actually let me just get rid of no users here or users for this role text actually so refresh and here it is working fine admin role is admin editor is mary and let's go to edit for editor and say bob as well is an editor save that go back to list and now it says merry comma space bob okay great i'm gonna get rid of bob for the editor but it's working fine okay that's gonna be it for this video see you in the next one in this video i'm gonna log down the admin controllers so that only the admin role can access them and i want the editor role to be able to access pages controller okay so let's get to it i'm going to go first to categories and open each one actually so all five of these so for the categories controller i'm gonna say here authorize so now as we know this means that anyone logged in can access this controller so to enable this controller for a specific role i'm going to have parentheses here and say roles and equal to the role so admin okay and i'm gonna copy this and paste it here for the pages copy and just import authorization save that so copy for products and copy for roles and copy for users and just import authorization here and here and here okay let me just build the product so i know it's all good f6 for me okay it's all good so let's check this if it really works i'm gonna go to the home page and i'm gonna login as john so john and pass okay so if i go to products that's fine i can access products but if i go to the admin area i'm in page let's say and i can't as you can see i'm taking to account slash access denied method and i'm not going to create this method and the view you can if you want but the point is it takes you there access the night okay so you are logged in but you don't have sufficient privileges to access this specific area of the website or part of the website so i'm gonna go back and log out and login as admin so admin gmail.com pass okay and now if i go to the admin pages i can so i can access h1 okay great and let me log out and if i log in as mary and remember that mary is the editor okay and if i try to access let's say pages i can't because mary is the editor and not the admin but i want the editor to be able to access pages as well so i'm gonna say here comma and editor so now both admin and editor can access pages okay and if i try to go to pages again account actually this is supposed to be admin pages so admin pages and they can as mary hi mary okay so this is mary logged in and i can access pages and if i go to categories i can't and products i can't either and users i can't and rows i can't but pages i can okay great that's gonna be it for this video see you in the next one in this video i'm gonna modify the two menus a bit to the admin one i'm gonna add the logout button and to the main one in the front end i'm gonna add admin area link in case is the admin or the editor that's signed in and i'm also gonna make the urls lowercase okay so let's get to it i'm gonna open the two layouts control comma underscore layout and the other one as well underscore layout okay so let's see which is which this is the front-end one and i'm just gonna get this logout lee here copy that and paste it here for the admin and this is just gonna say log out and i'm also gonna give it a class of logout okay and let me go to site css and i'm going to say here leenov item logout and position absolute top 10 pixels right pixels and list style none okay so let's see refresh here and it says log out but i'm gonna ctrl shift r to clear the cache and it's here so i have this logo button here now as well okay click that and i need to say let's see it's here i need to specify the area so asp area is empty okay let's try again go to the front end and i'm logged in as mary still so go to the admin area admin pages and log out and great i'm taken to the home page and i'm logged out okay now if i'm logged in as the admin or the editor i want to have here admin area link okay so i'm gonna go to the layout for the front end and i'm going to close this one i don't need it so here after logout i'm going to say if user is in roll okay so if in is enroll admin or user is in role editor and i'm going to copy assembly let's say this one here and this is going to say admin area and it's going to point to asp area admin with the capital a that is and controller can be pages and action index and i'm gonna give this a btn success class like so okay looking good let's see if i log in so i'm gonna log in as admin and pass and here it is admin area and if i click it i go to pages okay log out and if i log in and as let's say drawn and i don't see the admin area here okay great so finally i want to make all urls lower keys so now if i click let's say let's see here this points to the slug so it's lowercase as you can see here but um if i go to let's see all products for example you can see here it's uppercase and so on there are others as well these ones here point to slug i think so they're lowercase but in any case let's just make all of them lowercase which is the way it should be in a proper application okay so for that i'm gonna go to the startup cs file and in configure services here after add session i'm gonna say services add routing and options fat arrow options lowercase urls equal to true okay so let's go to the homepage and products again and as you can see it's lowercase now and that goes for each url now okay that's going to be it for this video and this project as well unless there are some bugs yet to be found okay so see you in the next one in this video i'm gonna get started with the rest api project and create that project and by the way i'm going to have this cms shopify product open here so i can copy some stuff from here anyway to create the project i'm going to right click visual studio here and visual studio okay so create a new project sp.net core web application or here next and i'm going to call this rest api create and let's see here for the template i'm gonna choose api and no authentication and leave this configure for https checked and create and here it is okay looking good that's gonna be it for this video see you in the next one in this video i'm going to create the pages controller and page model and connect to the database okay so what i want to do in this project is i want to manipulate pages from cms shopping cart project so i'm not going to create a new database and so on i'm just going to use the existing one okay so anyway let's get started firstly notice that this is a bit slimmer than what we had here when we started in cms shopping cart because when you choose api for the template you don't get models and views okay so views you certainly don't need but i'm gonna create the models folder you don't have to they have it here for example when you create the project in the root but i'm going to create the folder nonetheless so right click the project and add folder models okay and let's see here i'm gonna get rid of this controller and this weather forecast here as well okay so firstly i need that page model so right click mouse and add class page and i'm just going to copy from cms shopping cart so models and page and all of these without these validations okay i don't need those and now i want to add the database connection so first i need to create the db context class and i'm going to do that in the models folder so right click and add class and i'm going to call it again a cms shopping cart context because that's the database is going to use okay and let's see here infrastructure cms shopify context i'm just gonna get all this and paste it here get rid of categories and products and this is supposed to extend db context so let's see install package ef core latest okay looking good no more as quickly save that and now on to the startup file to register that service so here in configure services and again i'm just gonna copy paste from startup from this project where is it here it is so get this line services add a b context and add that here okay so this we need to import and for use sql server we need a package so i'm gonna go to tools and nougat package manager manage packages for solution and i'm gonna search for sql server and get this efcor sql server so rest api and install it stable accept okay it should be installed so alt enter here and using ef core okay looking good i need to add the connection string as well so open app settings json and here app settings json and here it is copy that and comma here paste it here save that looking good and finally to create the pages controller serracle controllers add controller pages okay here it is and instead of extending controller here i'm gonna say it extends controller base okay so let's see a base class for an mvc controller without view support because we don't really need views and i'm going to get rid of this action method here and just add the dependency for now which is that db context class which again i'm just going to copy from here so pages and this right here copy that and paste it here import okay looking good save that that's gonna be it for this video see you in the next one in this video i'm gonna do the get pages method and firstly i wanna talk about routes so if you go to startup cs in here and by the way i closed the cms shopping cart project because we don't need it anymore anyway here in startup for routes so these endpoints here now it says here endpoints and the map controllers and for cms shopping cart we had endpoints and map controller route and specify the routes there okay and here we have map controllers which means that we can specify the routes in the controllers themselves which is what you do with apis so let's do that so here i want to specify some route for this controller so i'm going to say on top of the class here route and in parenthesis specify the route oops so double quotes and i'm going to have it as api slash and in square brackets controller so the base route for this controller is whatever the domain is slash api slash and disk controller so pages in this case okay and i'm also gonna specify that this is an api controller so i'm gonna say here api controller and let's see what this does as you can see it says it indicates that the type and all derived types are used to serve http api responses okay so on to the method here i'm gonna say public async task and action result and for the type i'm gonna say here innumerable page and i'm gonna call this method get pages okay so i'm saying here that the return type is an innumerable of pages and that coupled with this api controller here is going to give me a json list automatically so i'm going to say here return await context pages and order by sorting and to list async okay and import this save that and start the project control f5 okay so i'm gonna go to api slash pages and here it is all the pages in json format okay great so to recap i'm saying here api controller to specify that this is an api controller and it should return api responses so it's going to give me json and here i'm saying that i want to return the list of pages and then automatically when i get that here from the database i get json here okay so it's really clean and nice and as far as routes go i'm saying here that the route for this controller is api slash whatever the controller is so pages in this case and because this method doesn't have any additional route specified here it's gonna default to this okay so the name here get pages doesn't make a difference so i can call this fruit and save that and refresh and i still get the same thing okay because the route for this method is gonna be this okay that's gonna be it for this video see in the next one in this video i'm gonna do the get page method and before i get started with that i just want to correct myself from the last video in the last video i made it seem like this api controller annotation is necessary to produce json but it isn't okay so this in itself is gonna give me json automatically and this api controller indicates as we said that the controller is supposed to serve api responses and it improves the developer experience for building apis but it's not actually necessary so if i get rid of it and save and refresh it still works okay but i'm just gonna have it there regardless so anyway on to the get method and before that i'm just gonna say here get and slash api slash pages this is okay so i'm going to copy this method and i'm going to call this one get page and say int id here and the url for this will be api pages slash sum id and also because this is an api i'm going to annotate each method with the request attribute even if it's just get okay so here i'm gonna say http get and here i'm gonna say http get as well but also in parenthesis here i'm to pass id in curly braces so that this method expects an id okay so the full url for this get page method is api controller which is pages in this case and then slash whatever is here so let's first get the page i'm gonna say here var page and that's gonna be equal to await context pages and find async and pass the id in here and get rid of this okay and this returns just one page so i'm going to get rid of this innumerable as well and the drastic page here like so and i'm going to say if page is now in that case i'm going to return not found otherwise i'm going to return the page so save that and let's check this out if i go to api slash pages and then sum id so i have one four three and two so let's say two which is supposed to be about us okay and here it is great and let's say one and i get home okay that's gonna be it for this video see in the next one in this video i'm gonna do the put page method and put is basically update in rest terms okay so i'm gonna copy this get one here get id and the url itself is going to be the same but i'm going to change here to put and this is going to be http put and i'm going to rename it to put page and i'm gonna be passing the id and the page okay so let's just first of all check that the id is indeed equal to page id so i'm gonna say if id is not page id i'm gonna return a bad request okay and if we hover over this we can see that this returns status 400 bad request okay so i'm gonna get rid of everything here and i'm going to say context and now entry and pass the page in here state and that's going to be equal to enter the state modified okay and then save changes so await context save changes async and there's no specific rule what should be returned after a put so i'm just going to return a no content which makes sense so let's see this returns a status of 204 no content okay and we're not actually going to be able to test this out right now because we need a client for that but this should work and one last thing i want to mention in this video is that you should get acquainted with these status codes if you don't know them already okay so if i just google for http status codes there's this link for example and you can see here that let's see to something is some kind of a success for something is a client error and five something is a server error okay and you have them here now in detail so that would be my advice but anyway that's going to be it for this video see in the next one in this video i'm going to do the post page method so i'm going to copy this put one and this is gonna be post and the url is gonna be slash api slash pages so change this to post as well and i'm not gonna have anything else for the url or the route and i'm gonna call it post page here and i'm gonna pass the page okay so in here i'm gonna get rid of these lines and just say context pages add page okay as simple as that and save changes async after that and now for the return again you can return really anything there are no hard and fast rules but this time i'm gonna return create a deduction so created at action and let's see here there are a couple of overloads so i can return here the action name and object value and route values as well and controller name so i'm just gonna use this first one okay so i'm gonna say name off and post page and page here okay so let's see what this says it creates the object that produces status 201 created response okay and again we're not going to be able to test this right now but hopefully it should work okay that's going to be it for this video see in the next one in this video i'm gonna do the delete page method so for that i'm gonna copy this put one and paste it here and i'm gonna say delete here and the url is fine here and the request is going to be http delete and the id so this is gonna say delete page and i'm gonna pass the id okay so in here again i need to first find the page so i'm gonna get rid of this and just copy from here so quantus pages find async by id and get rid of this here and then i'm going to say context pages remove page and semicolon there and save changes async and i'm going to return no content so 204 okay save that and we could test this out now but i don't want to delete any of the pages i have at the moment so i'm not going to test it now i'm going to wait for the client to add some pages and then i'm gonna test delete as well okay so that's gonna be it for the crowd and the api see in the next one in this video i'm gonna get started with the rest client and create our project and throughout that project i'm gonna have this product running rest api okay so that i can access these methods so anyway to create a new product i'm gonna right click here and go to virtual studio preview okay create a new project whoops back so asp.net core web application and i'm going to call this one rest client create and for the template i'm going to use mvc okay and an authentication and configure for https so create okay so here it is i'm gonna close this and i'm just gonna get rid of let's see in views home folder i'll get rid of that so delete that and adding controllers get rid of the home controller and the models get rid of the errorview model and in share the get rid of error cshtml okay so let's build this and just see if it's all good it's f6 for me for you whatever it says here okay it's all good that's gonna be it for this video see in the next one in this video i'm going to create the pages controller and model so in controllers folder right click and add controller and call it pages okay here it is and for the models i'm gonna right click the folder add class and call it page and from the rest api let's see page here just copy this and paste them here okay and i'm just going to rearrange this a bit like so so looking good that's going to be it for this video see you in the next one in this video i'm gonna do the pages index method and view so here's the index method but i'm gonna make it async and let's first of all add a comment here so get pages this will be so async here and task i action result index okay so first i'm going to make a list i'm going to say list of pages called pages and that's going to be equal to a new list page like so and import this actually that was the wrong import this should come from models okay so always make sure to have correct using statements here okay now so how do we communicate with the api in sp we do that via http client so i'm gonna say here using var http client is gonna be equal to new http client okay which comes from systemnet.http so first here i'll do the request so i'm going to say using var request and that's going to be equal to a weight http client get async and in here i need the full url so as you can see he request uri or url whatever okay so to get that i'm gonna go here i mean here to this api url and copy this whole thing so your port number is probably gonna be different but anyway just copy what you have and paste that here okay after that i'm gonna say string response to get that data so i'm saying string here because i expect to get a json string right so i'm going to say await request content read a string async and now i want to add that to the pages list so i'm going to say pages is going to be equal to json convert and this serial is object so i need to deserialize it from string and actually the type here so i'm going to say list page and response just another diamond bracket there and get rid of this one here okay that should do it and finally return the view so return pages view with pages okay so let's create this view i'm gonna go right click and add view index template is gonna be a list and model class will be page okay and here it is and i'm not gonna mess with anything here because i'm just interested in getting the client to work we modified all this to make it better in the cms shopping cart project so there's no need to do that here so i'm just going to leave everything as it is okay so here we'll open through the model and so on we know all this by now and i'm just going to change this lens here to use the tag helpers so i'm going to have an a here and the sp action is going to be edit and sp route id is going to be item id and say add it here and have a pipe here ctrl d get rid of this pipe and this is going to be delete okay so delete sp route id and delete here okay so hopefully that should do it let's see control f5 to run the project and if i go to slash pages okay here it is great i'm just gonna copy this and open a new instance of chrome and just have that there just so i have it into browsers okay so so far so good that's going to be it for this video see you next one in this video i'm gonna do the edit page get method and view so i'm gonna copy this index one and this is gonna be get page slash edit slash sum id let me just have a forward slash here as well okay so this is gonna be called edit and i expect to get the id here so in tidy and instead of a list here i'm gonna have a page so page page is gonna be equal to new page okay and this using our http client new http client i need that and request is kind of the same just this url needs to change a bit so i'm gonna add an ad here and say here slash pages slash and in curly braces the id right since that's the url let's see here the put one uh this uh get one with id that is and the put one we're gonna use for post edit but anyway that's the url so slash api slash page slash sum id just like so okay and then get the response and i'm gonna say here page and that's gonna be equal to json cover this serialize and this is just going to be a page and return view page okay so hopefully that should do it let's create the view and see so add view edit edit and page okay so i'm just gonna have this as md10 and get rid of these two so anyway in here let's see i don't want the id and i don't want sorting and this log actually either but i do want to pass the id as a hidden input so input hidden and this is going to be sp4 id okay and say here edit okay so let's see if this actually works if i go to edit let's say services and there's a bit of a problem okay anyway i'm gonna check what the issue is here and get back to you in the next video in this video i'm gonna fix that little bug we just had or i did you guys probably caught that so i just have here the add sign instead of a dollar sign so this here didn't work interpolation okay so now if i go to edit content let's say here it is it's all good or let's say about us and it works okay so let's also over here change this to text area and add ck editor so here i'm gonna get rid of this input and have a text area and get rid of this asp4 content and i need that ck editor cdn so let me just google it ck editor and here it is and let's see security four so right here and download standard okay here's the cdn finally so copy that and paste that in the layout in the layout view that is so here okay and here for edit say script and ck editor replace content okay so let's see if this works okay it really doesn't so let's see what's up oh the replace is supposed to be lowercase okay it's all good now and also let's uh change this to actually display html so in index and content here i'm gonna say html raw item content that is okay so let's see okay great that's gonna be it for this video see you in the next one in this video i'm gonna do the post edit page method and firstly i just wanna add to the edit view sorting as well okay just like so so anyway in here i'm gonna copy this get edit and i'm gonna say post here so even though this is put here there's no put in html okay so you can't save for this form here to have a put method the form can be either get or post so this is gonna be a post request and here i'm gonna pass the page get rid of that line so here i'm just going to say page slug it's going to be equal to page title and replace empty space with the dash and to lower and i'm not going to check if this log exists and all that okay i'm not going to do any validation i just want to have this actually work and we did all that in the previous project so you can incorporate it here in exactly the same way basically so i think it would just be a waste of time to spend all the time on validation and stuff okay so anyway let's see now i need this using var http client always but now before the request i'm gonna say var content because i want to actually pass something and this is going to be equal to new string content and in here json convert and serialize object so now i need to serialize it because i want to send it to the api right so serialize that page and i'm going to specify oops i'm going to specify encoding this is supposed to be capital e encoding like so which for some reason isn't working so let me see say here utf-8 and again capital e here using system text okay and say here application json okay that looks good now for the request instead of get async i'm gonna say put async and i'm gonna change this id to page id and also pass the content as the second argument okay i'm gonna have the response here even though i don't really need it in this case but you might for some project depending on what you're doing if you need the response or not i'm just gonna leave it there but i'll get rid of this page and finally i'm gonna return a redirect to the previous page okay so request headers refer and to string so let's see if this actually works and i'm not going to mess with the home page i'm going to go to let's say contact page okay i don't have http post here again okay here it is i'm gonna say contact 2 for the title and contact page 2 as well just to make some modification edit and i'm back here redirected and i can see contact 2 and quantum page 2 so it should work let's go back to list to make sure and it is and it did work that is so contact 2 contour 2 for the slug and contact page 2 for the content so it's all good and let's also before we added this back to contact without the tools let's use breakpoints just to see it in action so if i just exit from here and to use breakpoints you need to start with debugging okay so that's f5 anyway here's the put so i'm gonna have breakpoint there and here for the post i'm gonna have a break point here let's say in the in the get actually not the post so anyway let's do an f5 here and then f5 here as well so start with debugging okay and if i go here to actually this doesn't even matter i'm just gonna go here to pages okay so if i go to edit contact you can see i'm hitting this breakpoint here so i'm gonna go to continue and here it is modify this edit and you can see that i'm hitting now the breakpoint in the api project okay so here's the page and so on the whole shebang so continue and again i'm hitting this return view page get in the client and here it is it's been edited back to list and as you can see it's all good okay that's gonna be it for this video see you in the next one in this video i'm gonna do the add page get method and view and hopefully post as well since it's kind of the same as edit but we'll see so anyway to create the get method i'm just gonna copy from i'm not gonna copy from anywhere actually i'm gonna say get and pages create and this is going to be public i action result create fat arrow view okay so create the view right click add view and create create page here it is i'm just gonna get rid of this h4 h r and have this says 10 and get rid of the id and slug and sorting okay and change this input to text area so go to edit and copy from here and paste here and also the ck editor thingy as well copy that and paste it here okay so let's see and by the way i restarted both projects with control f5 so without debugging i mean you don't usually want to have debugging on because it takes too long to start the application every time it's too much hassle for me at least so i keep it like this usually unless i really need the breakpoints okay so let's go to create new and here it is looking good so i'm gonna do the post as well in this video because this was really quick so for the post i'm gonna copy post edit here and that's gonna be page slash create http post and this is gonna say create pass the page so i'm setting the slug and sorting as well to 100 okay and in here the content is the same as in edit so i'm not going to change anything there just this put async is gonna be post async and i'm gonna redirect to index so to forward slash okay so hopefully that should do it let's see i'm just gonna refresh here enter and say test page test page here create and yeah this was supposed to redirect to pages not to home but anyway if i go to pages i don't see anything and that's because the url here is wrong it should be i believe just api pages actually yup slash api slash pages okay and while i'm here let me actually change this to redirect to action then and index so it goes to pages index okay let's retry create new and test page test page create and here it is so test page the title slug is test dash page content test page sorting 100 edit test page 2 back to list and it's all good okay that's going to be it for this video see you in the next one in this video i'm going to do the delete method and finish this project as well okay so i'm gonna copy from get edit here and paste that down here so this is going to be get and pages delete and some id and delete here pass the id that's right get rid of this and here in here that is i'm going to get rid of this response and the page just have the request which is going to be delete async and this same url let's just double check in here so delete is slash api slash page slash sum id okay so that's looking good and i'm going to return this to redirect to action so copy and paste and i should hopefully do it so let's see refresh here okay delete this page and remember there's no confirmation now via javascript that we had in cms shopping cart so don't delete anything you don't want to i will delete this test page so delete and it's gone it's been deleted okay great that's gonna be it for this video and hopefully the product as well in this video i'm gonna make a new project for the standalone lessons okay so create a new project here and i'm gonna choose asp.net core web application next and i'm gonna call this project standalone lessons like so create okay and i'm going to choose the whoops mvc template no authentication and configure for https create okay here it is that's going to be it for this video see in the next one in this video i'm going to cover dependency injection we have already used dependency injection when doing the projects but there's more to learn about them let's first define what a dependency is a dependency is an object that can be used for example as a service it is any object that another object requires such as the cms tropical context we used in the projects for example and benefits of dependency injection are cleaner code easier code maintenance and easier unit testing okay so let's get started i'm going to create a controller here and by the way i have the product running is here just this home page that comes with the mvc template so i'm going to right click controllers and go to add controller and call this one products okay and i'm also going to create a model call product and this class is going to have just a string name and the decimal price okay so when you create a dependency or a service you usually have an interface and then a class that implements that interface okay so i'm going to create an interface right click models and go to add and class and i'm going to call this i repository like so and this is going to be an interface not a class and in here i'm going to have an innumerable of products called products and i'm gonna have a couple of methods avoid and add product and pass the product here and copy this one and this one is gonna be delete product okay now i'm gonna create a new class so right click add class repository and this repository is going to implement the irepository interface like so so firstly here i'm going to initialize a products list so private list product products just declare actually not initialize it i'm just going to have it like so and i'm also going to have a constructor to add some products to the products list so i don't have to use a database for example so in here i'm gonna say products is equal to new list of products and the new list product and add some products in here so new product and name can be basketball and price 399 m and duplicate this two more times this can be a shirt and this can be pants and the shirt can be 4.99 and pants let's say 19.99 and i'm gonna say forage add product and x okay so now here i'm gonna have a property innumerable product products and fat arrow products and i also need add product and delete product so let me just go here and implement interface like so just to get some code get rid of the body for this and this and this is going to be fat arrow and products add product and this is going to be fat arrow and products remove product okay okay so i'm going to end the video now because this is taking a bit of time and pick it up in the next one see you then in this video i'm going to continue with the dependency injection lesson so i just have the products controller here open and in here now i want to display the products in this index method okay so to pass it to the view i can do new repository and products right so i can do that no one is stopping me and i can also create the view so add view and index and list and product okay here it is and i'm just gonna change this a bit like so and just say here to string and c2 and let me also add that link to the main layout here so just copy this one ctrl d and this is gonna be products products and this is gonna say products and action is gonna be index okay so if i refresh now here it is so if i click products here are the products okay so you can do it like that but this is called tightly coupled okay and it's not good this is not a good practice it's better for this to be loosely coupled so the best practice is to use a dependency injection which means that the dependency gets injected into the constructor and that's it the controller that uses it so products in this case doesn't need to know anything about how that dependency works internally so to add a dependency injection i'm gonna say here private and read only and say i repository repository say tor to make the constructor and inject it in here so get this copied here and say here this repository equal to repository okay and i'm gonna make a copy of this and comment out the first one so now instead of instantiating repository here and asking for products i'm gonna say repository products so if i refresh i get an error saying unable to resolve service so whenever we want to use a dependency injection in the project we need to register the service in the startup file okay so i'm gonna go to the startup file and in configure services here i'm gonna say services and now i can say either add singleton or add scoped or add transient and i'm gonna explain the difference in a bit but let's say add transient now and here for the type i need to specify the interface and the class that implements it okay so i'm going to say i repository and repository and does have a semicolon there so save that and refresh here and now it works so i get the same thing but in a much much better way so here as i said you have transient and singleton and scoped and that is what is known as service lifetime okay so the difference is the singleton lifetime services are created the first time they are requested and every subsequent request uses that same instance scoped lifetime services are created once per client request so each new http request creates a new scoped service and transient lifetime services are created each time they are requested from the service container so with the transient service a new instance is provided every time a service instance is requested whether it is in the scope of the same http request or across different http requests okay so i can't really show you a difference now between transient and scoped but i can show you the difference between the singleton and transient and scoped so to do that in here i'm gonna create a new method copy that and i'm gonna call this one create and i'm gonna say here repository add product and new product name apples and price 150 let's say and i'm gonna return a redirect to action index okay so now if i refresh here and click create new i'm redirected back to index and nothing happens here because we have a new request and as i said scoped is created once per every request and the transient service provides a new instance every time the service is required so now we have let's see here transient and if i say add scoped and refresh and create new again i don't see a difference okay but if i say add singleton and again singleton services are created the first time they are requested and then every subsequent request uses that same instance so because of that if i refresh here now and go to create new and you can see that after the redirect back to index i have apples and again and again and again and refresh again and it's still there okay that's gonna be it for this video see you in the next one in this video i'm in this video i'm gonna cover environments and fallback http paths okay so there are three different environments you can use production staging and development and development is the default one so if i go in here to properties and launch settings json here is where you set the environment and based on the environment you can have different things in your views and so on so for example if i open layout and go down here after main let's say i can use the environment tag helper so i can say environment and include or exclude okay so i'm gonna say include development and in here i'm going to have a p and say development environment and default in parenthesis and duplicate this again and again and again okay so this one is going to be staging and this one is going to be production so just get rid of these defaults like so and this is going to say staging environment and this is going to say production environment and for this one instead of include i'm going to say exclude exclude development so here i'm going to say not development environment and get rid of this okay so if i refresh here now i see here development environment default so that's this right here and it's set here so if we change this to staging and refresh staging environment and not development environment okay and the same thing for production okay production environment and not development and once again if i go back to development and refresh refresh it says development environment and i don't have that not development okay so that's how you can use those and i also wanted to show you how to use fallback ahref paths so let's say here in the layout we're including jquery here for example locally from the project so it's in here in root lib jquery okay but we can say for example that we want to get it from a cdn if it exists and if it doesn't exist if the cdn link is dead for some reason then we want to get it from here but we want to try to get it from the cdn first so i can say here environment include production so let's say only in production i want to do that and i'm going to comment out this one here just for the lesson now so save that and let's actually refresh now inspect first and go to network and js here so make sure you have js here and refresh and there's no jquery here okay and if i uncomment this which isn't uncommenting with the shortcut for some reason save that refresh and here is jquery okay so once again comment it out control kc so as i said i want to get this from the cdn if it exists and if not only then get it locally from the project so i'm going to search for jquery cdn jquery cdn here it is magnified and i'm just going to copy like so because this copy to clipboard doesn't really work for me at least so i'm going to copy this thing ctrl c and paste it here okay so save that and let's see if i refresh here i don't get anything because i need to change the environment to production save that go back to layout and refresh okay so here it is it works the cdn works i mean and to use the fallback thingy i'm gonna say here asp fallback src so another tag helper and the fallback is going to be this so copy that path and paste it here so this means if this doesn't work if it doesn't exist use this okay but it also needs some kind of a test to know whether this works or not so for that i'm gonna say asp fallback and test and here you need to pass something that exists in the script some variable for example in here i can say window dot jquery so it's going to use this whatever this is to test whether this works or not okay so again if i refresh f5 i get jquery from cdn still but if i break this source let's say jquery 222 for example which doesn't exist save that and refresh and you can see here this failed but i am getting this one from the local host from my project that is okay so that's a really handy feature okay that's gonna be it for this video in this video i'm gonna explain what middleware is so middleware in sp.net core are components that are part of the application pipeline so whenever you make a new http request it first goes through all the middleware for inspection and then upon inspection the middleware either just passes the request to the next component in the pipeline or it performs some work request delegates are used to build the request by plane these request delegates handle each http request and you can see a code example here all middleware components are added to the startup configure method and the order in which they are added is very important because that is the order in which they are invoked on requests and the reverse order for the response asp.net core actually ships with a bunch of built-in middleware components such as authentication session web sockets routing etc everything in startup configure method is a middleware when creating your own middleware it must include a public constructor with the parameter of type request delegate and the public method named invoke or invoke casing which must return a task and accept the first parameter of type http context and you can see an example of that here okay so that's gonna be it for this video and in the next video we will create our custom middleware in this video i'm gonna create custom middleware so for that purpose i'm gonna create a new folder called infrastructure and this middleware class can go anywhere but i'm just gonna have it there so right click the project and add folder and call it infrastructure okay so now right click and add class and i'm gonna call it custom middleware okay so here it is and custom middleware doesn't need to extend or implement anything but it does have some rules i spoke of in the last video so we need that request to so i'm going to say here private and read only request delegate and call it next and add it to the constructor so say tor and copy this paste it here and say here this next equal to next and now we need that invoke or invoke async method i'm gonna use invoke so i'm gonna say public async task invoke and this is obviously an asynchronous method but i'm calling it invoke for no particular reason i might as well call it async but i'm just going to have it as invoke and say here http context so that's a must okay and now in here i can do some work so i'm going to say if something else await next invoke http context okay so if nothing happens here then it's just gonna go to the next request that it was supposed to go to in the first place so let's say in here i want to check if the url is for example middleware okay so something simple like that so i'm gonna say http context request path and tostring so that is equal to slash middleware if it is then i'm just gonna write something on the page so i'm gonna say await http context response and write async and say this is from customizer let's say save that okay so i've written the cust middleware but i also need to add it to the configure method of the startup cs file so i'm gonna go there and let's say after routing i'm going to say app and use middleware and the type is customizer save that okay so let's see i have the project running i'm gonna go to let's say home again okay it works fine let's say privacy and product so it's all normal but if i go to slash middleware i get that string from here okay that's gonna be it for this video see in the next one in this video i'm going to cover filters so filters are actually similar to middleware the main difference is scope so middleware only has access to the http context and filters have access to the wider mvc context but they are also used differently and there are also a few filter types so there are authorization filters which run first and they are used for authorization then com resource filters which can be used for caching there are also action filters and they run immediately before and after action methods there are also exception filters which can be used to handle exceptions and there are result filters which run before and after a successful result from an action method is processed okay so in the following videos i'm gonna show you some examples of the action exception and result filters in this video i'm going to show you an example of an action filter so what i want to do specifically is display the time in milliseconds how long it took for the page to load okay so i'm gonna open home controller and create a new method after privacy ctrl d and this is just gonna return a string and i'm going to call the method action filter and this is going to return copy that action filter get rid of these okay so if i copy the method name and go here slash actually slash home slash whatever the method name is and here it is okay working fine so now to create a filter back in visual studio i'm gonna create a class in the infrastructure folder so right click add class and i'm going to call this class time elapsed okay and unlike middleware this actually needs to implement i action filter but i'm also gonna say that it extends attribute because that's how you use filters as attributes okay so i'm gonna go here and here and implement interface and this is what i'm given so on action executed and executing and we said that this filters fire before and after action methods i'm just gonna cut this and paste it after executing okay so here first of all i'm gonna have a private stopwatch which i'm gonna call timer okay so in on action executing here i'm gonna get rid of this so we said that this filter fires before and after the actual method so this is before so here i'm gonna say timer is gonna be equal to stopwatch and start new and on action executed i'm gonna say timer and stop to stop the timer and now i'm gonna print a string to the page so i'm gonna say string result is gonna be equal to elapsed time and in here i'm going to say timer elapsed and total milliseconds ms and then i'm gonna get action result and append this string to it so i'm gonna say i action result action result that's gonna be equal to context result and in here i'm going to say object result action result so cast this action result to object result and get the value and append the result string and i'm just gonna have a space here save that okay so this is an attribute now so here i can say time elapsed okay get that using statement so let's see refresh and here it is action filter the string and elapsed time whatever it is and if i go to some other url it's fine it all works as it did before and let me also just add this to the main menu so i'm gonna go to layout and just add it quickly so get this li paste it here and this is action filter so controller home action action filter and it's gonna say action filter with the space okay it's all good that's gonna be it for this video see you in the next one in this video i'm gonna show you an example of action filter async okay so the end result is going to be the same but we're going to do it differently okay so in infrastructure i'm going to right click and go to add class and say time elapsed async and i have time lapse here just so i can copy paste some stuff so again this is going to extend the attribute but this time it's going to implement from i async action filter okay so now if i go to implement interface i get just this one method so here i had this one and this one and here i just have this one okay and they also have two parameters so i'm gonna get rid of this and i'm gonna say stopwatch timer stopwatch start new and actually we need to add an async there okay so start the timer and then i'm gonna say await next okay so we're going to start the timer and then i'm going to say a weight and next so this is going to go through with the action method okay so after it goes through with the method i'm gonna say timer and stop and i'm gonna copy this string result again copy that line paste it here and to display this string i need to do it a bit differently now so i'm going to say byte array bytes and that's going to be equal to encoding ascii and get bytes from the result and then to actually write it to the page i'm going to say await context http context response body and then write async and here i'm going to say bytes and 0 for the offset and the count is going to be bytes length okay so now if i go to action filter let's see actually i forgot to change the attribute name so now it's time elapsed async because that's the name of the action filter so just go back and action filter again okay elapsed time and this is it to refresh and it's working fine that's gonna be it for this video see you in the next one in this video i'm going to create a result filter and before i do that i just noticed that i have this errors here in the console and i'm just gonna get rid of this cross origin and integrity thingies and just have this like so in the layout refresh okay now it's fine and we might as well use the cdn so there's nothing in the console okay no errors i mean so anyway back to the result filter so what i want to do is i want this privacy method to return a different view right now it returns privacy and i wanted to return a view called change view so first of all i'm gonna create that view copy paste privacy and call it change view and get rid of this and the h1 is just gonna say change view so we know this is the view that's active okay and let's see i'm gonna right click infrastructure and add a class called change view and this is again gonna extend attribute and the implement i result filter okay so i'm gonna implement this interface so for executed i don't need anything and for executing i'm gonna get rid of this and say oops context result is gonna be equal to new view result and here i'm gonna specify the view name which is change view save that okay so if i go to home controller and privacy here and say change view let's see now if i go to privacy and here's the change view view let me just make that c a capital c like so okay great and let's also do one more thing let's add a custom header so i'm gonna go here and before i change the view i'm gonna say context and http context response headers add and the key is going to be let's say the name of the method and i'm just going to say here i result filter header okay save that so again if i refresh and go right click inspect and the network and refresh again and page so privacy here and response headers okay here it is that's gonna be it for this video see in the next one in this video i'm going to create an action result filter so basically a mixture of the action filter and the result filter and for that i'm first going to create a new method here so copy this privacy and get rid of the attribute here and i'm going to call this actually let's do it here below get rid of the attribute and i'm going to call it action result and i'm gonna say for now that i want this to return privacy view the privacy view okay so copy the name and i'm gonna go to layout and here just make a copy of this li and get this so action is action result and the action result here okay so let's see refresh and if i go to action result here is the privacy policy view so so far so good and let me actually change the name to action result mix just because asp uses action result so just not to confuse it copy this and action okay and here as well so action result mix like so and go back here and refresh and again and okay it's all good so anyway back to the filter i'm gonna right click infrastructure and go to add class and call it action result mix okay and this is gonna extend action filter attribute so we don't need to extend rgb specifically we're gonna get a whole shebang with just this class so again i want to have that timer and return a different view than i'm specifying here okay so first of all i'm gonna say private stopwatch timer and now i need to overwrite some methods so i'm going to say public override on action execution async so this one right here okay just say async here as well and get this down so it's easier to see and i'm gonna get rid of the body here so in here i'm gonna say timer is gonna be equal to stopwatch and start new and go through with the request so i wait next and then here i'm going to override another method i'm going to say public override and on result execution async okay and just say async here as well and get this down get rid of the body there okay so here first let's say timer and stop to stop the timer because the actual method has been processed at this point and then again i'm going to say context result and just pay this out a bit is going to be equal to new view result and view name is going to be time elapsed so i need to create this view and i'm going to pass view data as well so view data is going to be equal to new view data dictionary and in here new empty model metadata provider and new model state dictionary and in here i'll say that the model is equal to and that string so let me just get it from time elapsed let's say so this right here and i'm gonna say await next again okay save that and now i need to create this time-lapsed view okay so i'm gonna copy this change view and rename it to time elapsed and i'm gonna say here that the model is a string and h1 time elapsed view and pass the model data here okay so now if i go to action result mix and say here action result mix attribute save that let's see what happens i'm gonna go to products okay now action result mix and you can see i get the correct view and elapsed time so i get the model as well and it says here that's that it should return privacy view but in the filter we are returning time elapsed view with this model okay that's gonna be it for this video see the next one in this video i'm gonna create an exception filter so right click infrastructure add class and i'm gonna call it exception catch okay and this is gonna extend attribute and the implement exception filter so let's implement this interface and this is the only method and i'm just going gonna copy this body a bit from action result mix get this whole context result thingy and paste it here so i'm gonna get rid of the view name i don't want that but i do want this so i want to create the model okay and the model is gonna be context exception and message save that and in home controller i'm gonna create a new method here new action method and i'm gonna say here exception catch for the attribute and i'm gonna call it generate error and in the body i'm gonna say throw new and let's say not implemented exception okay so let's see copy that method name and i'm gonna go here to slash home slash generator and i'm actually missing the view so i'm gonna copy time elapsed and call it generate error and again the model is string and model here and this is just gonna say generate error view okay let's refresh and see now and it's all good here is the error message the exception message that's gonna be it for this video see in the next one in this video i'm gonna show you how you can display a custom 404 page and just a custom error page in general so anyway i'm gonna create a new controller right click add and i'm gonna call this error controller actually this was supposed to be add controller so add controller and error controller okay so i'm going to rename the method to http status code handler and here i expect to get an end that is the status code so i want specifically the 404 but i'm gonna have a default as well so anyway here i'm gonna have a switch so which that status code and if the case is 404 in that case i'm going to have a view back and the message actually call it error message and that's gonna say that page does not exist and break and the default i'm gonna have as well just to cover that as well so for the default i'm just going to say there was a problem and break and finally return view not found okay so let's create that not found view and this is gonna be in the shared folder so i'm just gonna copy this error view copy and paste and not found i'll call it i'm gonna save for the title here not found and get rid of the model and everything in here so i'm gonna have an h1 view bag and error message and just link to go home get rid of the href so this is going to have a class of btn and btm primary and sp controller actually i will have the ahref since this is gonna take the user home so i might as well just do that and say go to home page okay so we have this in place now but how do we activate it to do that i'm gonna go to the startup cs file and right here okay so this says if it's in development use developer exception page otherwise use this so i'm not gonna use that i'm gonna say app and use status code pages with redirects and in here i'm gonna say that url is slash error slash and sum so this placeholder is the status code okay and i need to create a route for this as well so down here i'm just going to make a copy of this and change it up a bit so name is going to be error and without this name key there so name is going to be error the actual url is going to be error slash and whatever the status code is and comma there and here i'm gonna say default defaults actually so new controller is error and action is and let me just copy it it's this okay so hopefully that should do it let's see now if i just go home okay now go to some page that doesn't exist slash aaa or whatever and you can see i'm taken to error 404 so 404 is the status code so it's all good and by the way there's this we're using here with redirects but there's also you status code with exit re-execute and does the same thing basically but it's gonna display this view in the same page that you try to access so if i go to slash aaa i get the same thing but the url doesn't change okay so depending on what you want to do you can use either i'm gonna stick with redirects and just make sure to have in launch settings here environment set to production because this is going to kick in in this else if it's not in development okay so here if is in development then it's going to use this otherwise it's going to use this so make sure to have the correct environment here and by the way i just want to mention that you have two profiles here and the difference is that this one kicks in when you start the project with control f5 or f5 which is what they always do and this should kick in if you start the application using a cli okay so some kind of a terminal with a command such as dot net run or whatever okay so the point is changing this profile here should work for you as well okay that's going to be it for this video
Info
Channel: Fast and Easy Programming
Views: 4,510
Rating: 5 out of 5
Keywords: asp, aspnet, asp core, mvc, asp core mvc, learn asp, asp for beginners, asp rest, web development, programming
Id: SbVc5YyMRAY
Channel Id: undefined
Length: 571min 20sec (34280 seconds)
Published: Thu Jul 15 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.