Basic Web Development With ASP. NET Core 5 | Trevoir Williams | Skillshare
Search

Playback Speed


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

Basic Web Development With ASP. NET Core 5

teacher avatar Trevoir Williams, Jamaican Software Engineer

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

    • 1.

      Introduction

      1:01

    • 2.

      Setup ASP.NET Core Project

      3:35

    • 3.

      Tour of Razor Pages Project

      18:57

    • 4.

      Understanding Razor Syntax

      12:19

    • 5.

      Message from Settings

      7:51

    • 6.

      Adding Entity Framework

      12:03

    • 7.

      Add Database To Project

      14:32

    • 8.

      Scaffolding Database Classes

      13:05

    • 9.

      Add Project To GitHub

      9:24

    • 10.

      Add Create Razor Page

      21:40

    • 11.

      Add Update Razor Page

      23:53

    • 12.

      Add Details Razor Page

      5:30

    • 13.

      Add Delete Razor Page

      22:30

    • 14.

      Using Partial Views and UI Enhancements

      33:11

    • 15.

      Add Changes To GitHub

      1:26

    • 16.

      Manage Database Changes using Entity Framework

      22:15

    • 17.

      Form Enhancements - Part 1

      24:20

    • 18.

      Form Enhancements - Part 2

      12:19

    • 19.

      Improve Data Collection Forms and Validations - Part 1

      26:35

    • 20.

      Improve Data Collection Forms and Validations - Part 2

      18:47

    • 21.

      Add Cascading Dropdown Lists with JQuery - Part 1

      24:03

    • 22.

      Add Cascading Dropdown Lists with JQuery - Part 2

      16:33

    • 23.

      Fix Data Label Displays

      6:42

    • 24.

      Clean Up User Interface

      31:15

    • 25.

      Setup Data Access Repositories

      25:57

    • 26.

      Add First Repository Code

      16:46

    • 27.

      Refactoring Pages

      14:20

    • 28.

      Complete Repositories

      21:24

    • 29.

      Repository Section Conclusion

      9:46

    • 30.

      User Authentication Setup

      10:54

    • 31.

      Extend Users Table

      4:53

    • 32.

      Setup Registration Page

      20:25

    • 33.

      Setup Login Page

      9:45

    • 34.

      Setup Authorisation

      9:34

    • 35.

      Add Authorisation

      3:09

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

92

Students

--

Project

About This Class

In this course, you will learn to develop an application using ASP.NET Core 5. 

This course will build on your foundation of HTML, CSS, JavaScript and C# programming. 

By the end of this course, you will know how to:

  • Build a web application with ASP.NET Core
  • Secure a web application with login and registration
  • Learn advanced concepts like Dependency Injection and SOLID Principles in programming
  • Connect your web application to an SQL Server Database
  • Use Bootstrap to beautify your website. 
  • Use JavaScript and jQuery in your website effectively.
  • Learn to Use GitHub for Source Control Management

Come with me on this journey and learn to build a dynamic, data driven and SOLID web application. 

Meet Your Teacher

Teacher Profile Image

Trevoir Williams

Jamaican Software Engineer

Teacher

Related Skills

Development Web Development
Level: All Levels

Class Ratings

Expectations Met?
    Exceeded!
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Introduction: Hello and welcome to this course, basic web development with ASP.net Core F5. I'm your instructor for VOR Williams and I'm a software engineer and lecturer in this course, we're going to be learning about ASP.net Core, which is a free and open source web framework. And it's also the successor to ASP.net, which is developed by Microsoft. In this course, we're also going to be looking at connecting our ASP.net Core application to a Microsoft SQL Server database. To do this, we're going to be looking at Entity Framework, which is a library that is specially designed for this kind of interaction. We're also going to be looking at source control, which is a practice of trucking and managing changes meet the source school will be using GitHub as the tool to facilitate this practice. This course assumes that you have fundamental knowledge in HTML, CSS, and C-sharp. If not, then I encourage you to check out my other courses on those topics. With all of that said and done, let's get started and I can't wait to see you in the course. 2. Setup ASP.NET Core Project: Welcome back guys. In this lesson, we're just going to be sitting up our development environment for our ASP.net Core application. And what I would like you to do is just hit Start and type in Visual Studio Installer. You already have Visual Studio installed. What we need to do is install some more workloads so that we can get to whip development. Don't, once you get that installer up, you should see a window looking something similar to this. And what you can do is click Modify. And when you hit Modify, you're going to see a list of potential workloads that you can install. So you already have the one for desktop development. What you would need is the one for ASP.net and web development. So if you don't already have it ticked, then he can go ahead and take it and then go ahead and install. So you can see that I already have mine set off to do that and you can install other workloads. But for this particular course or the next few lessons, we definitely wanted to have ASP.net and web development ticked and installed. Now once you have completed that installation, you can go ahead and launch your Visual Studio. And from there we're going to create a new project. So you can go ahead and create new project. And we're looking for an ASP.net Core web application. So you can just type in the search ASP.net Core Web App. So you'll see quite a few of them. And you'd notice that you have the web app which uses Razor pages. You also have the core web app which uses modal view controller. And then you have web API and you have a bunch of other templates. As you get more experience, you can experiment with the different templates. But for this, of course, we're going to be looking at ASP.net Core web app using Razor pages. We can go ahead and hit that. Go ahead and hit Next. And we're going to be calling this project car booting up. The general idea behind the projects will be that we're building an app that allows people to book or rent a car from a company as the needed. Sorry, it's nice and simple ability will be wonderfully complicated enough for us to get the fundamentals under our belts. So we can just go ahead and hit Next. And we're going to be using dotnet F5. And then you can enable razor runtime compilation, which will help us with our debugging and testing. We're not going to sit up authentication right now. We're going to do that manually later on so we can see all of the components that fit together with those settings in place. You can go ahead and hit Create. Now that we have our project up and running, what we're going to do is just take a quick look at what we get out of the box. We get this project structure. And when you hit Start, you'll notice that we get ready-made web app. We have the web app, we have our navbar at the top, the content area. So it's very similarly to what we would have looked at when we're looking at the basics of HTML, HTML development. At this point, we haven't written any code, but yet we have a webpage up with at least two pages for our viewing pleasure. We're going to be drilling down into the basics of what we get out of the box. While all of this is generated where we find what stick around and makes when we come up, we will be exploring the folder structure that we got with this web application and what all of these files mean and represents. 3. Tour of Razor Pages Project: All right, so we're back. We're gonna be discussing the dynamics or at least a folder structure and the different files that we get in our ASP.net Core application. You've already gone through and looked at HTML and CSS, and JavaScript and how all of those factors combine to give you a website and the fund net. You put a new project in a folder 12, you tend to put the different types of assets, the images in their own folder, CSS files in their own folder, etc. Well, this is just building on those principles. You'd have also seen that during the C Sharp coding exercises where each time you were creating a project, you've got a brand new folder where all of those files for the project would have been. It's the same principle or solution is in a folder by itself, the project is enough all by itself. And then there are different files and folders instead of that other folder. Let's start off with looking at properties. Properties gives us this file dependencies one has to do with libraries and frameworks. You'll see more of that as we go along. I'm not going to bore, you know, or overwhelming with that. But if you look at properties, you'll see that you have a JSON file that has some launch settings, so you don't generally have to modify this file on this, you are doing something very explicit, which we're not doing right now and we probably won't do for it within the scope of this course. But it's good to appreciate what is in here. You'll see that you have the application URL Canada defined here, where it says you have the URL at an HTTP address and then you have the SSL port, which means when we hit Start, we are going to be able to access the application by either typing in this URL or HTTPS colon slash slash local host with the port number of the SSL ports, you don't generally have to ever change this. So it's just good to understand it once again. Next major folder is our www root folder. So it doesn't really look like a folder based on hold. The other folders actually looked in this project structure, but what you would realize is that it has subfolders in it. So this is a folder that stores the static files for the website. So when we say static files, as you can see, is he the CSS folder, the JS folder, and another one called leap. All of those assets and the CSS files, JavaScript files, or third-party libraries that might be a combination of CSS and JavaScript or jQuery files. You'd want to store all of them inside of the www root because the application itself kind of maps this location and makes it very easy to access that location when you want to access the CSS, the JavaScript, or any of the other asset files. So you can see comes built-in already made with bootstrap, jQuery, jQuery validation, and another library for jQuery validation. So all of those libraries kind of come out of the box. If we want to add other libraries, which we will be doing later on, we can always right-click and we can go to Add. And then there is a feature to just install client-side library. When we get to that point, we can actually just use this and search for our library. And it would show us all the results, how we can just install it into the application without manually query and fishing. So remember when we were doing our jQuery inclusion and so on wet to actually go to the website, get the file and copy locally, or use a CDN. While using this library manager. We can do all of that here in just a few clicks. And it would actually just download it to our system or our project folders for us. Alright, so that's where all of our static files are really held. Know if you've ever seen an MVC application, you will be used to seeing model, view and controller folders out of the box. If not, that's fine. But the difference between the MVC or model view controller template and the Razor pages template is a fat that the way the pages and their assets are structured is different. With the MVC, you have the model which is a class file for too much. You have the view, which is the HTML file. And then you have a controller which was the intelligence. In Razor pages. What they've done is they give one folder called pages, and then each page comes with the CSS HTML or the HTML file, as well as R code file, which doubles as both the intelligence and the model. Let's take a look at the index page. The index page. Remember from HTML Basics, always name your first page index. Well, here is Microsoft living up to that very simple principle. So when I click on the index page, the CSS HTML file, then you will see that this is really just an HTML file. Yes, it has some embellishments, but once you get over that, which we'll discuss later on, you'll notice that they're the same tags that we would have learned from HTML Basics. The div tag, the image tag, the P tag, and every other target that you would know, they're all usable inside of this file, the dot CSS, HTML dot CSS file. It looks like the C-Sharp code that we just finished looking at. Alright, so we have the public class called index model colon. This is called inheritance. Index model is inheriting from the page model, which is a base class that comes built-in. But the fact of the matter is that this is called index model. And if you take a look back at the index class, you'd notice that at the top it says one, I am a page, and then two, it tells the model. You notice a declaration that my model is index model. That means anything that I anything that gets defined instead of index model can be accessed from the webpage as we build on it. You'll appreciate that a bit more. Most, most times when you see IRAs are page most, if not all times, then you're going to see them in pairs. You're going to see that is dot CSS HTML. I'm the one that is dot CSS HTML. Based on your Visual Studio, you might have them actually kind of nested by default, but you can actually toggle that nesting. Know it's disabled for me, I can enable it. I tend to think that this is a bit neater because when it's nested, I can just click and then I see the resulting file directly underneath that one. Sometimes it gets confusing when all of them are listed like that, but that's up to you. I'm just showing you that you can list, you can nest and disabled that at will. So as I said, every time you create a page, or at least standard result page, you're going to end up with both of those files knowing the shared folder. This is where files that are going to be used or accessed by all the other files, all the other pages, That's where these are stored. Let's take a look at the layout. No, you would have noticed that with our index page, let me just jump buffer with index quickly. You'd have noticed that the index page doesn't have that HTML skeleton structure that we had discussed from the basics. Remember we always start with duct tape and then the HTML tags and then hit and body and then we put the content, this goes straight to the content. What happens is that they are using what we call a layout. Or back in the day we call it a template or a masterpiece, where they lay out the temporary one time instead of repeating, repeating, repeating this template every single PDF, 20 pages, you have to repeat this template? Yes, on a basic website, it is absolutely necessary. But what they did was kind of abstracts that busy work. Remember once again, frameworks are setup to reduce the amount of repetition or reduce the likelihood of you having to repeat certain things. Because they know that you have to do with this HTML template every single time. When they developed a.the.net Core Framework, what they did was they created at one time and then they allowed you to render the different pH's inside of this area called render body. What really happens is that every page is always going to have the HTML tag, the head tag. This is set globally COC, it's always linking to the style sheets so you don't have to do that on every single page. You have the body tag which is going to have the header ear with the nerve, so you don't have to create enough on every single page. And then you're always going to have that div class with container. Remember we looked at that, that div class is equal to container. And then yes, you're going to see some new tags. You may use them, you may never use them at this point. You don't really have to. I'm worried about it, but the point is that whatever reason PG create with automatically get rendered inside this area, are inside of this overall template. To read you here will change the local, the Layouts, sorry, off all the pages globally. That's an easier way of maintaining your website because now you don't have to do it across all the pages like we would have seen when we're doing the basic HTML and CSS. All of that is kind of laid out here. You see the scripting inclusions at the bottom of the page and you can modify everything. So let us see, for instance, that what was auto-generated for us would be the View Data title of the page. If we go back to our index page, we would see that view datatype is equal to homepage. That is what would get rendered instead of your data title. So that's like a variable and a placeholder for whatever is putting on any pH that we have. Once again, title is what gets displayed in the browser in the tub. I wanted to change this from being one bit of text to car booking application. Bit more human-readable. But that's the title in the navbar, sorry, in the tub of the browser, then the navbar also has carb looking up written right here. So what I'm going to do is control and F5 and that splint to run without debugging. And when this app comes up, the first thing I want you to take note of is the fact that this is saying homepage. So that's loading the index page. In case you don't believe there it is. Index it says homepage, right? So it's loading the homepage or the index page dash car booking application. That's static texts that we put in the title. All right, what if I wanted to update this bit of text here? I don't want to say carb hooking up there either. So. I can go and find that bit of code which is right here. And I'm going to change it to car booking application. I'm going to save some humor. Always save. Unfortunately, I haven't seen them implement any AutoCAD in Visual Studio. That would've been very cool, but I guess they didn't, they haven't done it for good reason. But after making that change, I'm just going to Control, refresh my browser. And lo and behold, we see the change being made and that change once again, these global. So if I go on privacy for Go on home, every one of these pages is just inheriting from the overall layout. So I'm just going to also update it in the footer. I can just go over, change it in the footer. If anything, I wanted to cheat and shear. I mean, this is saying 2021 if I needed to update it to 2022 or not display only privacy, putting whatever I need to put in, all of that is being updated globally. So after making that change, I'm just going to refresh one more time. And you see the change is not reflecting. That is how easy it is to really modify globally right? Now if you wanted to modify the pages, well, it's just a bunch of HTML. So here's what's I went to do. I'm going to run antique the HTML from our basics class that we had on our index page. And I'm just going to slap it onto this new index page and let's see what happens. So here's our HTML from the basics. What happens once again is that we don't need all of these tags. It will need this, the HTML body all I really want. I don't even need the container. I remember we had to repeat Kantian or we have to repeat the novel everywhere. And then we add a div for the content. Well, what is in content is what we really need, which is what displayed on the page. We don't need a footer either because we have our footer. I'm just going to take all of this content. I'm not really concerned about the button's working are not yet. Well, what I'm going to do is just replace the default content that came with attempted with OER content from our course. I went to save that and then do a refresh look at that. Nowhere seeing that we can just modify the pages the same way. The only thing is that we don't have to repeat our skeleton every single time that is done for us. We just need the content. And notice all the classes still work for the displays of the buttons and for the dogs and the font. Why? Because the CSS file for Bootstrap is already included out of the box. They already are giving us that bootstrap file. Now, one thing is that we've gotten at five. This might change in the future, But right node that bootstrap library is, I can drill all the way down and see the physical fat. So when I said it, they make it easy for you to access. All you really need is this tilde slash. And then it will start giving you all of the folders in the hierarchy of folders from dub, dub, dub root. If I wanted to get to the CSS file that's in my site CSS, or I wanted to get to the CSS folder and I'll say today, then slash, and then it starts listing out all of the folders for me. I wanted to get to the CSS file. All right, so that's why I said all of your static files that you need to access can go into dub, dub, dub root folder, and that will make it very easy. But I was making the point that we can drill all the way down to the bootstrap file. And the Bootstrap version that we get out of the box is 4.3.1. In the basics we looked at using five, but then with this template we only get done bootstrap, bootstrap forests, sorry, which isn't a big deal because the differences between the two are not that big of a deal. And the documentation is always there in case you're using something from one that's not available in the other, like you don't see me trying to use Bootstrap for classes that are not in Bootstrap F5, you can always double-check on that. All right, so now that we have a better understanding of how the layout and the files work in general. And there are other files there, led view imports and view start. If you start basically says just use that layout file. So if we have multiple layouts, we can actually create another layout. If you wanted one type of user to see one layout and another type of user to see another layout or have different layouts per page, whatever it is, you can actually dictate which ones should be used. All of those things will come in due time. So I'm just going to continue the tour of the files and folders. And let's move on to the app settings.js. On the app settings.js, Zen is like a configuration file where we basically stipulate things like connection strings. You know, where to look for the database in static settings that we need to have in place to make sure that certain features run-up particular way. All of those things can get defined in that app settings file. We have the program.cs, which is very similar to what we would have seen in our C-Sharp in diverse, where every time we created a new project, we had a file called program.cs that tied up method called mean. It's the same thing, program.cs, And here's our main method. So all that happens is that when you hit IS Express our heat start, basically just calling program, calling the mean method. And the main method says build and run the application. So where does it know what configurations to put in place? It uses the startup file and start up here represents the startup about CS file, which is another place where configurations live. Here in the startup constructor, you see that they're doing what we call injection. So later on you get on a standard, but they're injecting an object of AI configuration which represents OER up settings.js JSON file. So that if whatever static settings we put in there, we can access them and then via code till it use this configuration when you're initializing this feature. So the starter file is basically where all the feature initialization occurs. Because you see here, we are seeing services dot address or pages later on when we're adding authentication and other things to the project, you'll see that we have to come in here and let it know. Okay, please use this module, please use this middleware, please use this feature we will be adding to this file as application grows. The startup dot css really just in-charge of dictating what should be in place by the time the application starts. So if I mess up anything in this file or a certain things in this file, what if I was to come in to this line as I don't think that line looks useful. And then I tried to run, then it will be getting this error saying that there is some mismatch between what I want to do and what features are available to me without trying to read this arrow word-for-word. It's basically I've seen that you are trying to run initialize the runtime compilation, but I didn't see where you told me that I can use the feature set for runtime compilation. That line I commented out is integral to the features that need to be called elsewhere in the application. So as you go along and you understand WHO.net Core works, you'll understand which libraries need to go where. Once again, this is not something you need to memorize. You just need to have a good idea of how this thing works so that when you want a new feature, you can go and research properly to find out what exactly you need to include to get it up and running. That's really it for the tour of the folder structure. When we come back, we'll start working a bit more on our interface and exploring how everything is wired. 4. Understanding Razor Syntax: Welcome back guys. In this lesson, we're going to be looking at how we can experiment with our arrays of peaches. I ignore pHs modifier or enough bar, and even look at how we can probably inject our upsetting into different places, similar to how we saw it being injected into the startup. So let us start off by scoping what we wanted to. So I'm going to create a very simple page. I'm just closing all the descript instructions. And then in pages I'm going to create a new folder. So this is always a good idea because when you have the different areas, what happens is that you have three main operations. Create, read, update, delete. So most times you want to create a folder. And then inside of that folder you would have the different pages to support the different features. Since we're doing car bookings, The first thing that we would need to probably have would be the cars. All right, so I'm going to have a folder called cars. And inside of this folder for the cars, I would have an index file which would represent the first page you land on when you vote to look at cars, which would be usually be like the list of cars. You have the edit, you have the delete and you have to read, which means I'm looking at a particular cars details. We're not ready to get into all of those complications. I'm just explaining why we have that folder structure that you will see that as a common theme throughout this course and in most web applications, regardless of the technology or the stock being used inside of cars, let's create an index file. So I'm just going to go ahead and right-click and hit Add go-to razor page. And what we're doing here is using the scaffolding tools. The scaffolding tools allow us to kind of generate files. I guess Microsoft has seen that we know the type of files that we wanted, our framework. And these are things that you would have to repeat manually h times. So here's the scaffolding tool. Use this and we will do most of the heavy work, putting in all the B6, making sure you don't forget anything and you can continue from there. So I guess that's why they gave us this nice tool. We're just going to create an empty result pH for no, I went to hit Add and I'm going to call it index.html, CSS HTML, and it's already there for me. So I'll just go ahead and hit Add. So now I have this new index file. So if we look again, we see pages slash cars slash index that I'm just giving you an idea of the URL because index will always be the first file. So when we go to slash cars, it will automatically look for the index file to load that first. Alright, so what we want to do here, I'm going to say View data. We're going to be typing this stuff manually ourselves. Went to say title. Remember that is viewed, datatype is a placeholder that feeds into the layout. And I'm just going to see cars list. Alright? What I want to do is just say H1, list of cars, some things simple. We're not ready to get too complicated or just sweating or appetites and understanding what, and if you look at this index page, you'll see that it looks very similar to the other index page. The reason that the index pages aren't touching is that the sub-folders that they're in are different. This index is in the general pages, so this is the entire whole page of the entire application. However, when we go into the slash cars, smash cars will have its own first page and it's index file is doing to be different, but it will see that they have the same direct 2s. This is a page, Here's a model and using the namespace there for this model versus the namespace for the other one. Once again, we get our code behind file for our index model. If I wanted to navigate to this new page, what I would need to do is modify my alleles and let the navbar have the new link. So I'm just going to copy one that exists there it is. I'll just copy the existing homepage link and change it all to see so we don't have an area. We have the ASP page. Where is the ASP paid? So the ASP pages not slash index anymore. It's slash cars slash index. Notice we don't necessarily need the extension where we don't need the extension. So this is where they kind of obstructed some of the things that we're used to with ba, basic HTML. Because if you look at it carefully, there is no H drift tag here. Not saying we cannot use a nature if we could. We could say h is equal to butt in. If we're going to see hf is equal to building the exact URL to get from application to page is the cars is going to be a bit difficult because we can't just see the filename would extension like we couldn't basic CSS and HTML. So what they have given us are called tag helpers, where they will say just 0 me based on the path of the folder structure. And I will generate that H ref for you. So ASP page is equal to, and I know I have to go to slash cars. So the first slash means the root of the application. Then I have to go to the cars folder. I didn't have to go to the index file. That's where this link should lead. It will generate the H riff at runtime. We will see that in a few. So I want this to say cars. All right, so now we have a new URL with a new page. And I'm going to go ahead and run like, oh, we're only doing user interface stuff. We can just do Control F5. We don't have to debug every time because this way is a bit faster. Now we are loading our application page. Remember that this is our homepage that we migrated from our static files. And if you wanted to migrate the other ones, and I will also probably be good practice for you. But right now we're starting off with this. And then when I click cars, before I even click cars, It's inspect element. Inspect element is going to show us the H ref for how we get there. If you look at the atria fear, it says EHR slash, that means go home. Slash cars means goal from the base URL, which is what we see in the browser, localhost with that port number slash cars. If we look at this one, you'll see localhost slash privacy. When I go ahead and hit the cars. Then I see that I'm landing on my new page, which is list of cards. You see it didn't even have to say especially index.html. Because by default, everywhere browser will go to the index page first. So that's really all it takes to build a new link and get the pages to see each other. All right, now let us look at hold the code file and the HTML file can interact with it. Right now I'm displaying that list of cars text directly on the page. This might not always be the case as we saw when we were doing the C Sharp coding. Sometimes the data that needs to be displayed or interacted with these dynamic from user input. It needs to be in a variable somehow, but we still need to display it. So what if I wanted to put this bit of text in a variable in the code file and then have it displayed. So I'm just going to cut it in the code file. What I'm going to do inside of our class is give it a new property. So I'm just going to say prop, press Tab twice and then I say string. And this is going to be hitting then on get one, the page loads this method called get is the first method that gets called. Every time you navigate to a page, you're going to hit that on, get whatever you want to prepare for that page. If you have to load data, if you have to sit on message like we're about to do no, you have to make sure you do that on Git, then all of that will be ready by the time the pH loads to the user. In this case, I want to see heading is equal to the tics that I just tied, which is list of cars. No, I'm preparing this variable. I'm making sure that the value is available before the patient or it's how do I make the value show on the page? Well, on the page itself, wherever I want it, which would be in between these H1 tags. And then this is what we call the eraser razor views or raise a syntax. Rather, the reason syntax allows us to kind of interweave or a C-Sharp code with our HTML code. Alright? So anytime you see an ad saying that is preparing you to write C-sharp code, because this is C-Sharp code that's a namespace from C-sharp. Yet we see HTML in the pH. Alright, so let me show you if I wanted to print something from the C-sharp side instead of the HTML, all I need is at sign. Basically since that directive that you're about to type C-sharp, no model is like a static variable or a global variable that represents an object of the model, which is the code behind anything that is public in the code behind file like this heading is is now available to me by me seeing model dot. Then I get all of the properties of the model including my custom ones. You'll see some that you didn't put in. No problem, don't get daunted, don't get flustered or anything. But if you look closely, you see hitting. That's the one I just created. I can just say model.py heading. And then if I save that and then refresh the page and what you can do while you're at this point, you can always just do a build using Control Shift and B. And then you can just refresh the page. You probably still have open from when you were debugging. But then you see here that we're still seeing a list of cars. And if you inspect element, there is no indication that it's C-Sharp or HTML. As far as Brazil is concerned, it's only seeing the HTML. So that's a polar offer is a syntax. We can dynamically put anything there. If I wanted to change the heading instead of maintaining the whole page. What if I had to display that takes multiple places instead of having the static takes multiple bases, I put it in a variable. Here. I change it from variable just so we know that it's working. And I went to do a build. Now once that build is done, I'm going to do a refresh. And then C, There we go. This stuff cars from variable. That makes it so much easier to make a dynamic page where we might have to change the text on the fly. We change it one time. And then we can just meet reference to it as many times in our code as we want. Unlike when we were doing our static pages and if we add up the tough takes multiple places, we have to go manually and change. It's everywhere. We can do that here, just nice and easy. So if I replicate all of those pages are cross or all of those tags, there it is. If I change it one time, it's changed as many times. All right, so that's a nice and easy way of understanding how the syntax works. How we can put something in the code file and access it inside of the Razor page. Next up I'm going to show you our first bit of what we call dependency injection. So what we're going to do is move this heading text from the C-sharp variable here. And we're going to put it in the app settings and then we're going to show a whole, you can just inject an abscess. These configurations, eat quite easily and display them on the page just the same way. 5. Message from Settings : So now we're going to be looking at how we can inject dependencies into our pH and access data in a very what we call decoupled way. So that is one of the four most and marquee features of downlink query makes what we call dependency injection, which is a very important principle in solid development. The D in the word solid actually means dependency injection. So solid is a bunch of principles that would help us to practice clean and good coding practices. And dependency injection is very important. And.net Core mix dependency injection, very, very easy for us. What we're going to do is in the app settings dot JSON file, I'm going to put in a new configuration. And once again, this is only for demo purposes just so we can understand how everything kind of flows and everything. So we're going to just sit a comma. And then I went to create a new section or a new node to say this is message. So I'm calling this one message. So basically what we have is like a key and value pair. So here I'm creating my volume and they're all Comma Separated. You notice that logging is the key and then the value is what we call an object. And the object has a key which has in another object, and each key has its own value. Every time you see a colon, what's on the right is the value, what's on the left is the key. And then comma separate the main nodes. So this is one Min node separating a load hosts, which is another load or Vardy key peering. And then that's comma. So we're creating our own valid key pair message. And then that is basic JSON syntax. Nice and easy to understand. Message is going to have the value. This is the list of cars. Lesson simple message. Nothing too fancy. Know, I said this in the opposite things. How do I access this text in the page to further display on the DNA to the user. So what we have to do is go to our index.js HTML file. I'm going to create another property. I'm going to call this one misses. So to duplicate its control D or Control CNV, similar to Visa Studio Code, but Control D also works. I have another property. I'm calling it message. And I need to sit message to have the value from the opposite things file, which means I need to access the config. So just like we discussed in the startup file, we were injecting the configuration object here. And then that allowed us to access anything, or at least I load them because we didn't write this. Whoever wrote this did that injection so they could access the configuration that will. We're going to follow that model. The principles of dependency injection one, you have a constructor, so we're going to write C TOR press Tab twice and then we get the constructor. It starts off parameter lists, which is fine. But then we need to tell it what dependencies it should help. So I'm going to tell it that it should be using I configuration. And if you want, you can just go into the startup about CS and you can take it I configuration. And we're calling the variable configuration. Red line means we need a library, so control dot and I can just go ahead and hit Enter. So it will include the using statement. So we just do that and get the using statement red line disappears. No, I need to initialize it. So I am telling it that I need the icon figuration from the inversion of control container or I will see container. The startup basically puts everything in that container between the startup on the program.cs file. They put those things in the container and then anywhere in my application I can access them from the container. So literally loaded everything, Everything from this app settings file into that container. And I'm seeing that I want access to that file, which is then obstructed to this type called Uyghur configuration. I need a local variable that I can use while on this page to access are like a copy. So what I'm going to do is just say control duct after putting it in the constructor. And then I went to say create and assign field configuration, and that automatically does that injection process for me. So now I have this local version just so that we can see them differently. I'm going to call this one an underscore. And I tend to do that with my fields on the score configuration and Control dots to rename everywhere else, so it gets rid of that error. Now that we have this configuration object injected one and initialized and accessible to the page. I can now say that my message should be equal to configuration. All right? The configuration object allows me to see, give me the key off what you want to access so that remember we just discussed key-value pair is what's the key I wanted to access the message. I'm going to see the key is message. Remember from IRAs, It's basically an array. This file gets basically turned into an array that I can now access using the key as the subscript. Once I do that, I now have a new variable called message that is accessible to my index page. So I can underneath the heading, put in maybe an h4 tags. And then we're just going to separate them with an HR tag. Gets a little fancy with it. And I went to say, I'd sign model dot. And then remember that once I say model.py have access to all of the properties that are inside of the model class, can access the message. No message is not just something that we typed and put in a variable. Message is coping all the way from upsetting. You see how far are we that is upsetting? It has the value and key pair for the message. And then on the page, load up. I'm seeing when you are loading this page, I want to get a copy of this object from the dependency or the IOC container. And I am creating my copy locally. And then on the fly I can see where the when the page is loading up, go to that local copy off the app settings file, get me the value that has the key message. When I do all of that, I can do a build. And I still have my page from the debugging earlier and you see it just updates for me? No. I'm seeing that message coming over from the app settings file. That's basically all Dependency Injection works as application grows. We're going to see definitely more of that. But at least this is a nice little gist of how you can actually access data from other parts of the application and still get them to display in the page. And your users wouldn't never be any wiser as to where this data is coming from, whether it's a database or it's a variable in the background. But we are in control so we know how to make it dynamic. The users only seeing what appears to be a very static page, load it to them. 6. Adding Entity Framework: Up until now we've been looking at some of the basics of how we can get Razor pages to display dynamic dates are coming from our C-Sharp code. The reality, however, is that we, in our scenario, we're not really going to be hard-coding these kinds of values and putting into variables and displaying, especially given the kind of application we're building, which is a car booking application where you're going to need list of cards which may be proven to change. A new car comes into the company, one gets retired, etc. Where we went after manage booking. So what we have to do is find a very dynamic way to actually store this kind of data. Then we need employ the services of Entity Framework so that we can one, create the database to interact with the database, and three, continue to build on the database. What we're going to be doing before we get into any of the complications is scoping old, what we need to store, we're going to make it relatively simple, but it's complicated enough that we can get good idea of what needs to be covered in a general scenario. What we want to do is employ the S in solid, which is separation of concerns. And the principle behind that is one, a method or a file should never have more than one responsibility. Which is why it's good that for every page there is a dedicated code file. So all the responsibility of this code file is for that page. What we're going to do is take it off just files and we're going to apply it to projects. Now that we're thinking about database interactions, what we need to do is create another project that is going to host or wholes rather all our database related objects. I'm just going to minimize or collapse the car booking up and went directly to solution. Click Add. And I'm going to create a new project. From this project listing, we're going to choose a class library. So if you don't have it in the recent project stimulates, you can always search. What we want is a C-Sharp class library. You can go ahead and select that and we're calling this current booking up dot Theta. So the name is going to signify that this is the data project. Hit Next, and we want to keep it as a dotnet F5 project and create a class libraries of very stripped down version of the C-sharp obligation are two C-sharp projects that were used to. Because you can see that this project just says that CSV file and the one classifier, it almost looks like a console application and exhibitors know program.cs. And if you even look in the actual project file, you'll see that all the tears is just the target framework. If you go back to your console, applications from C-sharp, you'd notice that they also have an executing instruction to let it know that it's an executable file. What we're going to need to do here is delete the first class, is define a few classes. So our, what we're doing is creating entities, which I really just could ask files that will get converted into database tables. So whatever, and we already looked at OOP, whatever it is that our properties of the data that we would want to store. We're creating our class to represent that, which later on we'll actually be turned into a table via the API is that Entity Framework allows us for now we just wanted to understand how we design the domain model. So our first let me model, since we started off with the cars, will be four cards. So we want a table to store the cars. What are the properties of the cars that we need to store? Well, in general, that might differ based on business needs, the different scenarios. So I'm just going to base it off my scenario. You might do a little more or fund it needs to do a little less than me. But as long as you understand the general scope of what we're trying to accomplish, then that is no problem. What we need to do is create our first lesson right-clicking the data project, I'm adding a class and I'm going to call it car symbol. Inside of car. We're going to make this class public. And then we defend the properties. The first property of any database table. If you haven't done databases yet, don't worry about me this as friendly as possible. If you are familiar with databases, you will know that the always starts off with a primary key which is auto-incrementing. If you're familiar with using SQL Server or so on. You know that you have to go through a few steps, you have to sit and identity constraint, you also have to let it know it the most increments IN1 and so on. With Entity Framework or in designing an entity that we know we're going to be using Entity Framework to handle. All you really need to do is call it ID. Just by doing this into different where we will know that, okay, this is the primary key and it should be auto-incrementing. That's it. So always have the primary key for every, most, if not all entities, 90% of your entities should always have a primary key value called ID. If you don't want to call it ID, then there are other things you might have to do. Using Entity Framework for it to recognize as a primary key. But between calling it ID or car ID or table name ID, those two will guarantee that Entity Framework Core was see it as the primary key. We have an ID, what does do we need? I'm going to say public int year, maybe the year of the vehicle is important, also. Going to store the year. And the next thing that I'm going to store is the string name, name of the vehicle, Toyota Yaris, etc. I'm just going to keep it simple and that's always throwing a ball. The car would have created our first entity. Now the next thing that we need in order to have Entity Framework recognize that this class should be a table, is called a DB context. So DB short for database context, meaning I am looking at all of the resources in the database, and I recognize them as such. We're going to be setting up the DB context. We're not going to be connecting or creating any database just yet. We're just setting up the groundwork, right? No. I'm going to right-click once again and add another file, new item or class rather. And I'm going to call this one car booking. Db context, niacin, easy name to remember. Carb looking up DVI contexts, just another class file. Now the DB context is going to once again be public. And it's going to inherit from a base class that is given to us by Entity Framework called DB context. By just typing DB context. And if you give Visual Studio few seconds, you will notice, okay, wonders and error book tool, in order to use the DVI contexts, you need to install a package called NTD framework. So you have Entity Framework and anti different work Court. We're using dotnet Core, so we have to use Entity Framework Core, which is the latest and greatest of Entity Framework. Now the cool thing is that we need to use a package manager. So instead of us having to go off and find things manually, Visual Studio comes with a package manager called New get. We have two options. We can allow it to just go ahead and find it for us and install it. Or we could manually go, right-click and hit Manage NuGet packages. So it's good to understand all of your options because the developer who knows it needs Entity Framework would probably just start here. You would probably just go to NuGet, go over to bros. And then he would see all of the packages available to him. And then he would actually see that you have Microsoft dot Entity Framework Core dot SQL Server. And there's the one that was advertised to say I have a bunch of other ones, but we're not going to be worried about the ones you don't need. So actually, we're going to be using SQL Server databases into different work core is actually open source and available for most database engines. In MySQL, postgres SQL sequel light, all of those are different database engines or providers. Into the framework provides APIs that allow you to use C-sharp to talk to any one-off doors. However, if we, since we're using SQL Server, we can just go ahead and install the into different work core dot SQL Server, which will give us the SQL server APIs as well as the base library for Entity Framework Core. So I'm just going to use NuGet package manager. And all I have to do is hit this down arrow. We can choose version. We see that this is the latest stable version. Don't need to modify that. Hit Install, give you a few seconds. You might get pronounceable licenses and agreements. And as those co-morbid, just click OK and accept and denote time it's installed. And when we go back to the CS project, you will see an item group gets added where the package references being put in. That's fine. We can leave that we let it do its thing in the background. But now when we go about two dB contexts and control, we see that we have the ability to just add the namespace. That was our first taste of how we can use NuGet package manager to add libraries that are inherently missing. Go ahead at the using statement. Now we have the DB context. In order for us to let the DB context know what the tables need to be. We need to add public DB sit. Then we tell it creates a Db, Db cities Entity Framework. Talk for a table. Context represents database, BB sets represents a table. We have to provide the model that these tables should be based on. Well, we have created our model in the form of car. Someone to say database. You will have a table in modeled off car. And you should call it cars when it's created in the actual database. So let's just look at that again. This entire class represents our database at all the assets that will be there to views the tables, stored procedures, etc. Once we want to add a table, we want half to create the model that the table should follow. So in the case of car, we gave it the properties we know how to do the class by no. This is really just showing how our class looks like a table in terms of database development. We just created a class with all the properties, all the fields that we know our or table needs to have the datatypes. And then we're telling the database context that I need a new table or a DV set of type car. And I wanted to call cars. When we come back, what we're going to do is set up on my aggression where we actually tell it one, generate code that will create the database and we'll assess how that looks and into we will actually generate that database and see that all of this is going to work out in the way that we are talking about it. No. 7. Add Database To Project: Welcome back guys. So now we're going to be sitting up or actual database. We already set up our context, which basically represents a connection to the database. We already created at least one entity or a table for that database. No, we need to once it up what we call a connection string. And then to create what we call a migration, which would be the set of instructions that Entity Framework could use to inform how it is going to go about creating the table and the database and any other assets that needs to be created accordingly. Let's go up to our app settings from our car booking. And what we need to do here is add our connection string. Now the syntax for a clinician stream looks something like this, and I just added it right above logging. So remember that all of this is one big JSON object. I'm adding a new key called connection strings. And then that key has an object value which takes another key value pair, default connection, and then this is the value. So let's just go through what this value has. This value has a server and the name of the server is pretty much the machine name or the name of the database instance. If you're not so familiar with databases, that's fine. We have a built-in database provider with Visual Studio called the Local DB, MS. Sql local DB, you can always get to these databases by going to the SQL Server Object Explorer. If you don't want to have it on the side like I do, they can always go to View. And then you can look for SQL Server Object Explorer. So this gives you instant access to that database instance and you can just drop down and it's local DB slash MS SQL local DB on the B2C, all of those databases server is equal to local Debian, write it exactly how you see it. Open parenthesis, local DB, close parenthesis. The double slash is because we need to escape the slash. If we have one session, you get that error. We need to have that double slash in the context of this file and MS SQL local DB. Then we have a semicolon and then we state the database is equal to car booking up on the score db. Now once again, we haven't created this database as yet, but we know what we want the database to be called, so we're letting it know at that point. Later on you'll see that you have trusted connection is equal to true and multiple active results sets is equal to true. So this is security-related entities for usability. So you can just go ahead and replicate all of that. Now after we have flipped in our connection string, we need to let the application or that at startup you are to use this connection string for the database. Still in our web app, we're going to jumbo to the startup. Then in the configure services, we are going to register our DB contexts thread. So I went to say services that add DB context. And then I'm putting in the name of the DVI contexts. And as I'm doing this, I'm looking across and seeing that I have one name here and another name on this side. So actually this is what I wanted to be called. I called it Car book Up DB context in error. I went to update it, right? No carb looking up DB context of the filename and then update the class name accordingly. All right, so now that that refactor is done, I feel a bit better and I can go back here. So services dot IDB, context, and the way I've typed brackets with the name of the DB context, and then we have the options. So obviously this is not really registered what we're trying to do, hence the red lines. So what I'll do is control dot. Then it is going to indicate that I need to add a reference to my car booking up data project. Alright, so we have it in two different projects to differential will call assemblies. And right now the Visual Studio or the solution sees that. Okay, I'm trying to reference something that's not in the current project, which I see it in another project. Would you like to add the reference I went to say yes, please go ahead and add the reference. Once I do that, you'll see that this null changes to that color that indicates it knows what file it is and everything is. Okay, but then I still have another error I'm just going to control. And it's telling me I need to add a using statement for Entity Framework Core so I can go right ahead and do that. No, I have no more errors. That is hole. We add that bit of code with the options to use SQL Server, like I said, Entity Framework, core can support multiple database engines. So we're specifying that we're using SQL Server here. And then I'm looking in the configuration. Remember, all of that was injected in earlier, the configuration dot get connection string. So that's a built-in function of the configuration. They were looking for the default connection. So that default connection, and then he's getting that value. So anything you may have called this if you didn't want to call it a default connection to me, I wanted to call the carbocation up connection, whatever you call it, we just have to get that connection string here. Now let's do a quick bill just to make sure that we haven't broken anything to build was successful. Let's carry on. So the next step I need to actually generate this database. So like I said, we need to do a migration and then we can actually generate the database after the migration. What I'll do in data project once again, I am going to jump down to Manage NuGet packages. Then we're going to look for the package Entity Framework Core dot tools. If you don't see it listed here, ready like it is for me, you can always go ahead and search for it. I see it here. I'm just going to go ahead and install it as usual. Go ahead and accept any terms and conditions and know that it's installed. Let me just give you a quick background as to what these tools allow you to do. If you look at the description of the library, it says that it enables US, you to use commonly used commands. You have add migration, that's what we're about to do. You have dropped database, get DVI contexts, migration related things, scaffolding related things, and script migration and generation unrelated commands. So these are all the commands and these are actually powershell commands that we will be executing using our Package Manager console. That Package Manager console, if you're not seeing it where I have it in my taskbar, once again, you can always go to Tools and then you get packaged manager and a Package Manager console. Alright, so once you do that, you'll get a window similar to this, where it's asking you for the command. What we're going to have to do, one is change our default project or a data project because that is where our DB context is. That's where we want our migrations and everything gets up is related to live. I went to change the default, predicted a data project. And then I'm going to say add dash migration and he can even press Tab to complete it for you. Then I'm going to call this initial migration. After that, I just press enter. It will rebuild the project and then I am getting this error. Don't problem. So it says my startup project doesn't reference this library, that's fine. This package is required for into the Framework Core tools to work. So they're actually telling us what's wrong. No problem. So Miss misstep biomass apart. Let's fix it. Let's right-click on our web project. Use NuGet. And I'm just trying to show you how easy it is to get these levers in once they're missing, you get more than likely has them. So go ahead, go to NuGet and then I'm just going to paste the name of the library that it said. Once again, you can always just search in the, typing the search bar. And then once I get it, I can just install it. When that is done. I will now go back to my Package Manager console and I'll just press up. So when you press the up arrow, you get bought the most recently, attempted, at least attempted command. So I'm just going to press up, get bought that migration, press Enter again, and nowhere getting another error. I'm not going to hide these arrests for me because sometimes you tend to forget some of the steps and it's good to see the errors and know how to work through them. I'm clearly forgetting some steps here, but that's no problem as the error scope, we will fix them. So this one is saying that there was an arrow accessing the hosting services. And there needs to be some constructor that takes the configuration being passed in. So let me explain exactly what this is saying. Bach, when we would have setup in our startup class that each should be using the DB context. And I would be passing in these configurations. So the options, pretty much this whole object here called options, would allow us to put in a number of different settings that we want to go for and hold the database interacted with when the application starts up your entity. It's a very simple one, right? No, the only option here is that it should use the mixture on string. However, this is not enough because while we're tended application use this database and disconnections, you are this DB contexts and linear represent the database that is our disconnection and string. We need to let our DVI contexts that it is supposed to be relative tool, whatever options we're passing in. Let's jump back over to our DB context and we will create a constructor. So I'm just going to read CT OR, and press Tab, Tab. And what we have to pass in here would be DB context options. And the DB context options would be relative tool or car booting up DB context. And I'm just going to call it Options. And then we have to let the bass note that it should use the same options base of course represents or DB contexts from the inheritance. This is completing that whole dependency injection hierarchy that I would've alluded to. Where when the application starts up, once again, we're seeing use the DB context that is found at this file and give it these options to govern it without what we just did with all these that line of code. The DB context was just sitting there in la-la land nowhere letting you know this is what be aware of the fact that options will be passed in. And also possible with the DB contexts, which is the base class given to us by EF Core. So now that we've done that, let us try once more to door migration. And at long last we have a successful migration attempt. Alright. Now we have this initial migration. Finally, as you would get a new folder called migrations that you can collapse. But every time we do a migration or every time we make a change to the database, adding a new table or column or changing something, we have to do a migration. The migration file will generate and say these are the changes are these are the things that I'm going to do. And then we can execute them and it will keep a history. So it's a nice way to keep a history of all the changes being made to the database. If at any point we make a change and that's not quite what we wanted unwanted to remove the migration, then you can literally run the command removes migration, which would just undo the most recent migration. Just a quick scan through up to what this migration file is saying. It's saying, well, we have a class called migration builder, which is being initialized or positon rather. And then this builder allows us to create the table name is cars. So remember that whatever name you put here, that's the name of the table going in. So it's saying create a table with the name cars and the columns should be ID. Remember I said once you call it, ID will automatically know that its identity, its primary key. It's already sitting up all of those constraints on the ID column, four rows. And it will create the year and the name columns for us. That's in the function. Then you have a don't function, which basically says, this is what I'm going to do to undo this. So if we ever make ACI instead the database and then the underlining realize, oh snap, that's not really what I wanted after me. I have to change this quickly. And you want to undo the migration as well as the change to the database. Because what happens is that if the changes already applied to the database right now this file is not no no database exists. This is only an instruction file to see when the database this is what I'll do. If you already have the migration and you're already applied it to the database, then you will have to roll back the migration before you can remove it from the history. This don't method is what contains instructions and say, well, these are the changes that were made. Well, this is all I'm going to undo them. So this one says create a table with all of those things. The Undoing for that would be to drop the table. As we go along, we'll see more of that. So don't worry too much about it. I know we just wanted to make sure that we have already to be excreted. So the next command that we're going to run is update database. You can go ahead and execute that. And then once that has been successful, then we can go and verify that our database was created. So go back over to your SQL Server Object Explorer. Then expand, go into databases, and then you will see the car booting up BB. In that database, you'll see cars for a table and EF migrations history as a table. So this table trucks all of the migrations that have been applied to the database. And then we'll see this database filling out as we put more and more tables in it. 8. Scaffolding Database Classes : All right, so now that we have done our migration, we've created our database. The next logical step would be to load the application to interact with the database. Because, well, you wouldn't want to necessarily send your users into your database to be able to manage the car's. Not everybody will know SQL, not everybody will understand how to operate in that environment, which is why we have user-interfaces, our web applications, that allow us to conduct different operations in a more user-friendly manner. Alright, so what we're going to do is explore whole reason pages makes it very, very seamless for us to actually generate user interfaces to interact with our database. We already kind of started building old pages for the cars. And what would happen is that we have the index page and the index would usually be the list of cars. And then you would have the other what to call crowd pages. So C and corrode represents create, our represents read. You were presents update, and D represents delete crude. Basically every application that you will ever use on your mobile app in your fridge, whatever it is, all they're doing is crude operations. They are looking into view something. Remove it if you don't want it, change it if you don't like it or will create something else. So corrode, that is the crux of every application. So what we're going to do is create the crowd pages for our cars. Because we need to be able to manage a fleet, want to view all the cars into data BSO on to delete the ones that are no longer here. Maybe somebody made a typographical error, you want to update it, etc. I'm actually just going to remove this first index page that we created for cars. What we're going to do is a scuffled and new index page using Entity Framework. So what we can do is right-click or cars folder go to add a Razor page. Then when this dialog box comes up, we have three options. We have the emptiers, a pH, which we already looked at. We have the reason pgs is the Entity Framework, so we'll use that one. So this next dialog box allows us to say what is the name of the PGY1. We're replacing the index bits. I can just tell it index then the template would ask, Okay, Do you want it as a list template, edit template. So we can actually scaffold load of form or the whole display for whatever we want. So in this case we want the list because the index page, generally speaking, would have the list of whatever datatype or data you are showing. The more model class would be next. And the modal class means walked model or table model am I supposed to use when generating this page? So I can say car. We'll do, we'll do is go ahead and generates code so it can display the different data points of the car entity. The data context plus of course would be RDB contexts, which is where all of our database objects will be leaving. Anyway, we don't want to have to change any of these other settings and we can go ahead and hit Add. Know I encountered this error you might not have, but we're going to work through this Arab because since recent versions of dotnet Core, this error has occurred during the scaffolding procedure and it's good to understand at least hole you can get around it. It's very frustrating at times, but let's just work through it. So there are few things that are recommended. One, you need to and I'm just going to cancel all of this. One is to go to Tools and go to NuGet packages, Package Manager, sorry, and then the Settings. And then you're going to clear all you get caches. So go ahead and hit that. Next is to go ahead and build or clean the solution. So we're going to run a clean solution. And that brought it needs to do. And then I'm seeing that I have two errors here. I have an error regarding the versions of the packages. So that is generally what causes this error. When the packages are the versions of the packages that you might be using bullet necessarily match up to the versions that the scaffold or looking for. I'm not sure why. This is one of those more irritating parts of both what Microsoft, the Microsoft team has been doing in recent times. But let's just work through the Soul. No, my packages and I'm just going to click on the project file and I can see that my packages are at 5.09. So what I'm going to do is drop them to 5.08. So in the CSV file I can actually just change the pockets. So this is another way you can change bucket version so you can change it right here. But then if you're not entirely sure of what the version numbers are, no problem. We'll use them you get for the next one. So you can always just go down to the new get package manager in for that project itself, look at the installed versions, and then you'll see which versions you have. And then you can change that version. So I'll just drop version 2.08 and then click Update. So you can just do that for the dotnet core completion and design packages for the Entity Framework. After I have done that operation, I see that I have built successfully. So I'm going to try the scaffolding again. I'm going to right-click cars had Razor page and then page using Entity Framework and we just fill out the same things that we just filled out. So index template is list, model classes, car, and then go ahead and hit Add. All right, It's like that's another area. This one at least is a bit more informative. It says there was an earning the selected code generator to scuffled, install this particular pocket. So okay, no problem. Let's just go ahead and follow the instructions. In the background. You can see that and you get to actually started installing that very pocket. I'm going to just try this one more time. This time we have lift off. So I don't know that that was quite a cycle of trying to get distinct work. Once again, it happens when certain versions are released, but the underlying mechanism in Visual Studio has not been updated to know that this is the library version, it should be used. So you might have a bit of back and forth with that. And like I said, there are not many resources online to walk you through exactly what to do. Those steps, generally speaking, will work for you. But what we end up with is index file. The code file. In the index value, you see that a lot of HTML has been generated for us. And in the code file you'll see that some amount of C-sharp has also been created for us. So let us briefly discuss what is happening here. In the index file. Let's start with a code file because that's listed. Look at what we're looking at here is injection. So remember that we did form of dependency injection earlier with a config file because the config has something we wanted. We didn't want to create a whole new instance of the config file every time we want something. So instead we're taking that shared copy that was registered in the app to be shared across everybody. So in essence, when we would've gone to our startup class and registered RDB contexts, we were already starting it to be shared across application, thus making it a candidate for injection anywhere we want. So this is us injecting an instance or injecting the sheared version of the context and initializing our own private copy in this file. That's dependency injection on one-on-one. Anytime you want to do dependency injection is going to look something like this and you can inject multiple things as at-will. So you're not limited to only one thing at a time. Now that we have the, in the context injected into our index, what we're doing here is creating a list object of type car, so it's just a collection of car. All right. We should call this cars really. So I'm just going to call this cars because it's a list. And I tend to get very specific with my naming, at least that I pluralize it. If it's singular, then it's singular. So you can rename it to use Control dots and allow it to reflect till all the other references for you. And then what we have is on get. So remember what we discussed when the page loads. We have the on, get on, get here is being fired. Once we navigate to this index page, is going to automatically call this method. This method sets up any data or whatever we need for the page, just like we did with the config and initializing our variables in the previous example. So here I'm saying that my current list of cars should be equal to. And then we're going to await the results of calling the context dot cars table and getting all the elements. So this is classic Entity Framework. Entity Framework gives us access to the database through this context file. Whatever tables we declared, because remember, cars, we put cars there, that's ours. That's all it's doing. It's saying context, give me the cars. And then the way Entity Framework works is that this is what we call an executing method. It's seeing list async means the actually give me everything in the table as a list. And then we're storing that list in our local variable or property called cars. After all of that is done and the page has been set up, let's jump over to our actual HTML. So on the actual HTML page, it knows that it's an inexperience, gave its didn't name index find all of those little things are because we call the pH index. We get to complimentary Create New button, right? So we have a link to the create new. Of course that page doesn't yet exist, but that's fine. We get a table, and that table has a header or a head section with the header rows. So we have the table header for the year ahead, afford the name. Then we have another table header column that is empty. And then for each item that came in, the model dot car, model up cars, that is our list of cars. And then we're using that for each loop to go through each item in that list of cars we're seeing. Give me a display for the year, give me a display for the name. And in that third column that had no hitting, who could have called this actions, maybe what's in that third column, give me three links wanted to edit, want to delete, and one, just view the details. And each one will pass over that ID. Remember, the primary key ID, That's what uniquely identifies a column in the database or that role rather than the database. And then we're just tying that to the button so that when we click Edit on any one of these roles, we know which ID we're going to view. Let us just take a quick look at what was generated for us. Here's our pH. This is our new page. We see here that we have something looking like a table. If you're not familiar with all tables, look in Bootstrap, then that's really what they're going to look like. But we have the table, we have the column for you, we have name, and then we have that empty column which is going to have the links. What we don't have is data. Yes, we have the page we've up that Create New button up top that index flood so we can start customizing this page to what we want to. Instead of seeing index up top, we can say hires list of cars. That's basically what we had last time when we do that and see if we see it refresh and change. Alright, so what we don't have would be to create new. We don't have any data and we don't have any of the other pages either. When we click Create New, it's going to just loop around because there is no page for creating new one, we come back, what we're going to do is create a GitHub repository for this project. And then we can continue developing on our features. 9. Add Project To GitHub: All right guys, So we're back and what we'll be doing in this lesson is sitting up or GitHub repository for our projects. No, GitHub, we've gone through this. It's very, very useful tool or platform for keeping a copy of our project one and keeping the history of our project. It also allows us to collaborate with our colleagues or friends on a project very easily. Museo Studio, microsoft bought GitHub years ago and ever since the integration between Microsoft tools and GitHub, namely visual Studio and you already saw Visual Studio Code. Those integrations have really matured and become very, very, very powerful. So we're going to see how we can send up all of our project information using Visual Studio to GitHub and in keep them in sync. So it's really simple to get that done. What we can do is just look in the bottom right-hand corner of our Visual Studio. And we will see this button that says Add to source control. So you go ahead and click that and you'll see get. So get towards installed on your machine automatically when Visual Studio was installed, if it wasn't already installed from when you did this exercise using Visual Studio Code. But no, they'll say create a Git repository and they'll setup the local repository. And then it'll also allow you to create the GitHub repository out of the box. So if you're not saying Didn't go ahead and sign in, you'll probably get prompted to login with your GitHub credentials this point. But then from here, you can indicate that you want a private repository and that's fine for now. You can leave it as private of actually realized that when you untick this unless they fixed up bulk buyer, no, but it wouldn't create it on GitHub if you didn't make it private, not entirely sure why, but you can always go back and change it to public if you so desire. We leave it as private. We don't have to put in a description or anything else. And they're telling us what the URL tweet will be. So you can go ahead and click, Create and push and give it a few moments. And I didn't get any overt indicates that it was finished. But if I look in the bottom right-hand corner, I'm seeing that the button to say add is no longer there instead of centimeter path, it's telling me that I have a master branch. It's going to be what we call the remote. Remember, we had set up that remote, which basically has that link to the remote repository. It has pending changes and commit that might be on pushed know in resources. You'll see that all of the files in the Solution Explorer null hub, little padlocks, these button lots indicate that the version that is on your machine has been unchanged since the last update from the server. So if I go in and meet any adjustment and I'll just make a slight adjustment to this file. Then you'll see that it gets rid of this red tick. Means yes, this file has been modified and we have another panel called good changes. If if it's not where it is on my screen for you, you can always go to View and you will see good changes. All right, so once you open get changes, it will show you the files that are changed and waiting to be committed. So you have your commit message, so it does say modified index file. Then the easiest way to do this would be to commit all and seeing what this does is push and pull. It will send over your changes and pullover any new changes that might be there? No. There are situations where you might end up conflicting with your colleague, meaning you made a change to this index page. He or she also made a change to this index page. And then one of you checked in before the other. So when you are checking in your modified version of the old one, GitHub is realizing that the version it has is different from the version that last gave you. And then that would cause a conflict. At that point, you'll have to do some conflict management and resolution. We can discuss that later on as a project grows. But retinal this, just keep it simple enough To know that we can create or repository for changes synchronize and when we do commitments and you will see it will commit it locally and then synchronize the local commits with a GitHub commits automatically bringing down anything that you don't have that is currently in GitHub. Real entry. That's how easy it is to code as a group. So each of you could easily log on to this project on GitHub. I'll just show you through Maya colon. So here's the carbo King up that was just created one minute ago. There's the chicken that I just made modified index file. Right? No one it's private and two of them the only person. So if I wanted to Well, keep it private but share it, then that's as easy as going to settings, go into Manage access. They might ask you to confirm who you are. And then after confirming who you are, then you can invite collaborators. Inviting collaborators is as easy as typing in the person's name. So I have another, I'm trying to defend my other YouTube, a cone so I could just demonstrate what that looks like. But you can actually just look for the username of that burst art. I was just deal with random usernames. It can just find the username of another person, go ahead and add. And then they would accept the invitation, and then they would be able to also push and pull from the project in order, let's say the new person on the team, or even if you lost your code, let's see, your machine crashed. I need lost their local project and you need to retrieve it from GitHub. The same procedure as somebody who was just added to the project and they need a local copy to start working. All you really have to do is go to code. And then you will see open with Visual Studio. Once you do that, it will open Visual Studio on your machine. Then indicate that you can clone from the repository. So this is a repository location that's the URL for GitHub shore. This is your local past. Now it's showing red because I already have that local path. That's a project that we're working on. No. So once again, if it was our first machine, then you wouldn't have this problem. Or if it was the first time you are getting this project, you wouldn't have that problem with the path. Even if you already have the project, all you have to do is change that fast and it would pull into a different folder if you really wanted a copy. After you signify where you wanted to clone locally, it just click Clone between Visual Studio and GitHub. All of the project files that have been uploaded up to know will be downloaded to your machine and synchronized and then you can start working. So that's how easy it is for teams to start collaborating. If you want to make the whole project public. Serrano's private, meaning if this URL and I tried to grow suit and I'll just open a new incognito window. If I tried to grow suit, I will get to a 404. It technically doesn't exist versus one of my public projects. Let me just find one that I know is public. If you were to get that URL and browse through it, then it would show anybody can browse to public repositories on GitHub. But once it is private, nobody can, when you're working on your serious predicts the money-making projects, they don't want to share your intellectual property with sharp, make it private. But then in the true meaning of open source and collaboration and shearing, then you probably want to have a few open projects because then that can also double as your portfolio for your suitors or your future employers When they wanted to see what kind of projects have you done and just get an overall idea of your skillsets. Overall, GitHub is a wonderful tool for just meeting new people, you know, looking at what other developers might be doing. You can follow people. People can follow you as you post. People can start your repositories or make their own copies of your code because maybe you are doing something that somebody else is interested in doing and what you are doing are half done, can help them. In the true meaning, once again, are hopping on open source community for collaboration. That is what GitHub brings to the table. So go ahead and what we'll be doing is making shorts or a cone. So every time we get a piece of functionality in, we will be synchronizing with the repository because once again, it will give us the history of everything. So if we make a mistake and something stops working, we can always roll back to the previous version. What you don't want to do is leave too many changes between the versions that you're checking in. 10. Add Create Razor Page: Hey guys, welcome back. So now that we have an idea of how we can generate the code to view the cars or any detail in any table. Pretty much what we can do is continue along this line and fish out all of the crowd activities. So corrode once again since we're create, read, update, and delete. So right now we have one of the red options in the form of the index, but we have no data in the database. We have two options. We could go into the database, put in the record, but of course, in realizing or it wouldn't be doing that, wouldn't be encouraging our users to do that. So instead, what we're going to do is continent to scuffle with all the pages. And next up is the Create page which would clinic those to the database allows to use the UI into our data and then have it viewable from the index. In the same way that we generated the index file. We're just going to go right-click cars, add Razor page. And I'm going to do another result page with Entity Framework. Now, once again, you could just scuffled all of these, but I wanted to do them one by one so we can assess the different bits of code and hold they all come together to give us the full crud functionality. So Razor page using Entity Framework, I went to add that one. And this time I'm going to do a Create. I'm naming the page create. The template remains that creates it will give us a form or a model class will be our car. And we can leave the data context stress, go ahead and hit Add. And it generates our scuffles that page for me. So I get the pitch fund as well as the code file we're used to that now, just remember that if you get any errors about it and not being able to scaffold, we just went through that activity with the index. So in-between the lessons, you may have been inclined to update your NuGet packages and then that would probably cause some disconnect with a scuffle older. So if you're getting that error, just roll back to the previous version or a version before the one at your null at. And try again. And as you drag and if you keep on getting the area, just keep on crease scaffolding or dropping the NuGet package version and attempting to scuffled. So now let us assess what we got through this scuffle, the activity for the Create page. We have our code behind file, which were always a class inheriting, inheriting from Page model. And then we have our contexts being injected in. Then on get, it's just saying return pH. In other words, we don't have anything that we need to necessarily load up for the Create, so we don't have to go and Fitch any data in order to show the form because they're just going to be showing an empty form to the user for them to actually create a record. So the onset is empty, there is nothing to return here, that's fine. We also have this property called cards. So we have public car and it's an object of the type car, and then we have buying property. So bank property here basically tells the Razor page that on the form, whatever input is given for any property that is inside of this class, it should watch it. Once it is submitted, then it's going to hit that post. Anything that is boned, it's going to be watched so that when we hit the post it will actually scrape all that data, matching data for the car properties from the form. And so we can process it in that on post. Here we first check if the model is valid. The validity of the model can be a number of things based on what data we're asking for. So in the case of creating a car, it would be absurd to a low, a car to be entered without a year and with OTA name. Or at least maybe the name is the most important thing. The ear could be optional. So we would definitely want to make sure that at least the name is present before we attempt to send anything over two the data piece. So that if models state is valid here, basically does that check for us to see what are the validation rules? Are they emit if not, just reload the page. I'm going to show you in a few seconds. Hold that will translate to each showing what is wrong with it. But if it is not valid, just reload the page. Otherwise, what will happen is that it will go to the database context, go to the car stable and add the new object of car. See that that's the same objects that we said Ben property four. And then after that it will save changes. So that's all Entity Framework works. It says one, telling me which table and tell me what you wanted to do. So in this case, we wanted to add and we want to add a car. And then once we're augmenting the data, meaning where adding something, deleting something, updating something. Once we're changing something about the data, we have to call save changes. Now you'll notice the await. When I double-click, I wait, you'll see that there is this other title called a sink. So in asynchronous programming, you're going to see a lot of that async task off the type I actually results in. Notice that the onset is just i oxygen result. This one is task action results because it is an asynchronous function. The reason it is asynchronous is that it is making an async function call to the context. So it does have a non Async version. Just save changes. But then that would require us to make a few changes to our method and all these things. But if it generated that for you, it is always going to try and give you the most efficient code based on what it's capable of. So that is why we're getting the asynchronous versions of these methods after it has saved changes and everything is okay, then we redirect to the page index is even the generated code knows that it should be looking for a page called Index. That index page would be right here on the same level as create. After everything is done, it will just redirect to the list and you'll see your newly created a record in that list. Now let's take a quick look at the HTML file that was generated for us. It's not a lot, It's a small form because the table doesn't have that many records to sorry that many fields to fill. What we get, we get one, we get the car. If we could actually just redesigned essentially create car. That's our H1 tag, remove that H four. And then we have some Bootstrap divs. We have a div with a class called rule, and then in there we have a class called call MD4. So that means it's taking up four columns in the rule. In Bootstrap, the grid system is such that you can create a rule and then you can have col, dash a number what you have up to 12. So you can have as many call divs instead of a row up to 12. So you could have 12 ones or three, fours or four threes. Alright, you can mix that much and just not choose to have any, right. So if I wanted to form district right across that what I've seen from the HTML section of this course when we just created the form, we gave it all the form tags and so on a stretched as far as wide as possible, then you wouldn't have to specify any col md. So you can experiment with that. Look at the documentation for the different column measurements, and we can experiment with that and see what that looks like. But most importantly is our form. Then in the form we have this div that says AASB dash validation summary on model only. It also has another mode that sees all. All right, So sometimes I tend to just meet that all. Sometimes you love model only. That's fine. I mean, you'll see the benefits of one and not the other, although is more global. So I would just recommend that you use all when you have two. Then we give it a class with tics danger. This section of the page actually gets filled with any validation errors that were present when we said if the model state is not valid, return the pH, so that's automatic. So the model state is actually trucking to see, well, This is the entire model and this is being boned. When data is entered and on Post, it is going to truck all of the data that was entered here via the form. You'll see that you have two inputs. One for my car dot year. I don't want to put dot name so we get the label, will get the input, and then we get the spun with that validation message being built-in. So two places, the validation messages will show up underneath the input and at the top of the pH in a gen summary. Whenever it gets posted a cheques, was it valid? If not, we return to page when it reloads that page. Between the validation summary and these validation spans, we will see all the texts that will indicate why something was not voted. What I'm going to do is flip this around because it's our farm. It was generated for us what we can change it their own. So I went to put this form group for a name above year. This thing that flows more. It's putting the car name and putting the year. That's optional at this point. And then we have the Create button underneath with BTN class will be ten dash primary. And you can even extend this sense it btn block, it stretches right across the entire page. Then we have our list back to List button. So if the person got this far and initiate, Okay, I don't want to create the car anymore. They can always just hit back to list, go back to the index. Underneath all of that is a section for the scripts. And what happens is that this whole validation workflow that I just described, it's really a combination of us adding validation rules and I'm about to show you how that works. And some partial or sorry, it's some scripts that gets rendered on the page. This bit of code, this is rendering partial async for validation scripts. If we look in the shared folder, then you'll see that exact partial underscore validation scripts partial. There it is. And if you look in that partial, you'll see that all it has two script tags for jQuery dot validate. So to jQuery libraries, which we saw in order www roots. I'm just trying to show you how everything is interconnected here. We have the jQuery validate, how the jQuery validate on obtrusive. So we have those, we just created a partial or the framework generated this partial for us that automatically has references to that. Anytime it will generate a form for you or even if you create your own form. Later on, we'll be looking at how you can create your own farm from scratch or your own page, then you can actually just use this bit of code to get that kind of validation workflow in on all parts when we wanted to tell it what fields are valid or sorry, it should be validated and against what rules we have to go over to the actual model that is being used or the actual entity. Putting these attributes are data annotations is as simple as going above the field that you want the rule to be applied to. And then using square brackets and then we will see required. So that's our first rule that is saying that anytime data is supposed to be entered against any page that is modeled off car or any form modeled off car. The name field is required. That's step number one. What other rules might we have? We might also want to say that it's string length should be, and then we can see a maximum length of maybe 50. So no car name should exceed 50. Let me put that to 150. And then we could say that if it doesn't get to exceeded, want an error message of my name. Is name is too long. Something that we can also set a minimum length so the person shouldn't be able to enter anything with one character, you know, stuff like that. So you can actually just string them along right above the field. Now, putting these rules against the debtor entity, because this is the actual entity that is being used to generate the table like we saw when we added a DB set. We added our migration. When I put these here, I'm actually going to be affecting the database. So if I generate another migration at this point, and I'm just going to generate one. I did validation rules, press Enter. And when you do that, always remember to change the default project to the data project. But once that is done, then you can see here that the goods an altar column bit of syntax. Here it's saying alter the column with the name, name because that's the one that we just set the rules above. Then the type is still, the type is int varchar 150. So before it was in var char marks, note that whereas sitting as string length limitation, it is going to change the datatype in the database to know that even then it cannot store more than 150. All right? No, it's no longer inaudible because now we made it required. So before it was true, it was not a blue. We could've lifted MTU. The database would not have a problem. The database itself with actively refuse it. If it is null, then if nothing is provided, it will give you a blank string as a default value, but it cannot be null. However, on the client side, it wouldn't never even accept the blank string because it is required. So when we go and test or form on the index page, I'm going to hit Create New and then we have our forms. So because of the call MD4, you see that it's only stretching to up to four. What we can do, just explore this. I'm just going to inspect elements that we can play around with this width. If I made that called MDA eight for instance, you would stretch to eight times. So from where do we see the EHR? Lines stretching from left to right, that's as wide as the 12 columns. So I know he's going to be taking up eight of the 12. If I didn't specify a width, then that's what it would look like. It would be kind of tiny. So if we wanted it to fully extend and then we could just say col md. So I'm just going to do that here, equals calls. So this is a nice, seamless way to test what it would look like before you actually meet the code change. So nowhere seeing called called dashboards. So you can say col dash AMD, T12, meaning on a medium-sized screen, T corp dot size. Or if you just want it to be universal on every screen and take up that mode size or not mathspace, you can just say col dash T2 are called dash the number. So here we see it's stretching ultimately from left to right as far as possible. And then we have our Create button, which is btn block. If I just tried to create this point. There we go. We're seeing our validation working. So nowhere getting that validation summary at the top and then we're getting the validation messages below. No, we didn't tell the year field that it was required based on our rules. What I'm going to explain why you're going to see this. So it's good to understand these nuances with all the valid dish on and what fields are automatically validating, so to speak. Because year is an integer and not a nullable int. So by default, when you see int in C-Sharp, it means that it can never be null. All right? So nano means empty. But then an int can never be empty. An int is always going to default to 0. So that means when we submitted just nor I attempted to submit any, if modest it is valid. It was not valid because the integer did not get a value at all. It didn't even get the 0. As far as it's concerned, it is invalid. So if I had put a 0 there, the validation message goes away. If I tried to create, it is satisfied as much as 0 is not a valid year for us. Zeros a valid value compared to null for an integer. I'm just trying to explain all the different data types might have their own kind of validation going on based on hold. They work in C-Sharp. But ultimately, if I don't put anything there, it's going to automatically just say, well, it's required. If I tried to create, it won't go any further. And if you want further proof, I'm just going to put our breakpoints right at this line where it checks, is it valid? We click Create, it's going to hit that breakpoint. Well, it's not going to hit the breakpoint know because of validation is actively watching. So let me go ahead and create car. This is actually in my old car. Beautiful GAR, go ahead and hit Create. And since there are no active validation errors just yet, what we have is this check to see model state is valid. It is valid. This is saying if it is not valid, then return to paid. So since it's valid, it's going to go ahead and add it to the database. I'm just going to remove this breakpoint, hit F5 to let it continue. And then it does that redirect to the index page, which then runs the query to see and get me all the cars into the database and display them. That's how everything is interconnected. So I'm going to try and do another create. And I'm just going to put this breakpoint, just take and see what's happening. We're going to click Create and you'll see it doesn't even hit the breakpoint because on the client side it is actively refusing because the validation rules are actually setup for the fields based on the rules that we sit. If we highlights or inspect the text box for the name, we see here that we have data Val equals true. So all of these are generated by the JavaScript. So between our rules that we set up in C-Sharp and the JavaScript libraries on the client said all of these attributes got added to the text-box. So data Val equals true means I am supposed to do data validation on this field. The data of length. That means the error based on the length, is the error message that we had typed in. The max is 150. So all of the little rules that we had set up, you'll see them being applied in the forums of attributes here. And we did not have this extra code. And if you look back at our HTML file, it is still the same ischium. We didn't type it in and it hasn't modify the file itself. All of this is being done on the fly each time the webpage will load. That we've done, all of the, what we're going to do is just update the database because it just created a new migration. And that's something that we're going to be doing a lot anytime you make a change to one of the entity classes, one, you make a migration where it will document what change needs to happen. And should you remove the migration, what cheat and needs to be undone or changes. And then after making the migration, we go back and we say update database. So you can actually use tab. If you type some of you to do is press Tab to finish the rest of it update database. And if all goes well, you'll see done. Now, there are times you may get errors. Maybe some of the changes that you want to apply may conflict with some of the data that's already there. Sometimes that happens, but as I said, anytime these errors come up, we will work through them together. So you can have a good idea of how to troubleshoot something. Should it come up? When we come back, we will continue with our code adventure. So far we have the Create, we have the r, So we have the c, we have the R in the form of this index page. And then we can do the edit next. 11. Add Update Razor Page: All right, welcome back guys. So now we're onto our new activity, which is to set up the edit page. So the edits would be the UN crude update. The time we are going to edit something, you're basically making updates to the existing data. So continuing along the same vein of scaffolding will rightly cars, cars folder, go ahead and heat. There is a page, a page using Entity Framework. And then this one we'll call it edit. My rationale for using these page names. Why I said edits instead of update or I said index instead of list. You will notice that in the index page, those are the page names. It's expecting to see that being said, however, if those are not the page names you want, you can always change them. So if I wanted this to say update instead of edit, then that will be fine. I'm going to call it updates. I went to change this template from Create to edit so we get that edit form and you'll see the difference between the create and edit templates. Modal class is still car, data context means the same ad. Then we get our two-fifths. So we get updates, CSEA, enamel, and the model file behind it, snow, this is update. But if I go back to the index page, the code that was generated is looking for the ASP page is going to want to see is edit and not update. So okay, fine. I can just make it null Each look forward to update page. I can also change the text if I want, because this is just an anchor tag. What is it takes that I want displayed? I can say I want to display update, but I'll leave it at edit because update is not as user friendly or users don't really relate to the word update as they would edit. What you present to the users. Always important. But you can have a little leeway with your pitch names. But that's all I wanted to demonstrate by not Nimitz edits, put naming it, update. You want to be careful if you're going against the norm, then you have to meet more and more to facilitate your implementation. However, otherwise, if you go with the norms, your need for customization is greatly reduced. Let's get back over to our code file for the update CSS HTML file. So it's pretty much the same thing one where injecting the database context too, we have the same kind of band property, property that we saw in the Create. So we are going to have the former. We are going to have fields for the car on the forum. We needed to watch for the changes to the property values so that we can process them on post. Notice, however, that are on GitHub has a lot more action going on, then we will have become accustomed to, and let's just walk through what's happening here. One, you'd notice that this is async, so they made it acing this time, and it has a parameter for int id. Now notice that this int has a question mark beside it. So previously I would've mentioned neoliberal ins versus int. So int means that it is not optional, it has to be at least 0. However, there are times when you might need a null value in the variable that is supposed to be an int. In this situation, they're basically saying somebody can try to navigate the update page without providing an ID. All right, so that means that when it hits here, that ID value would be null. The first thing it does is to check if the id value is null, then return not found because I can't find nothing. No means nothing. And if you're telling me you want to edit a record with nothing as its ID. And we already went through hold that ID is that unique identifier in the database? It's a primary key. That's what the ID is. If you tell me you want to edit a record icon, turn to the idea of the record that I'm going to tell you whether it's not phone and I can't find it right. So anytime we get those 404 pages on any website, basically what this is all they're doing, they're returning, not phoned. All right. If no ID is provided, then I cannot find nothing. That's pretty much what we're seeing to the user. However, if it goes beyond this, then we can assume that the ID has a value. So we try to find that value in the database. This is basically saying, go to the context, go to the car stable. So go to later be sorry, go to the car stable and get me the first or default record where the ID matches the value that is coming in. This is what we call a lambda expression. All right, so put too much. M could have been any Tolkien, this could've been the word record equal w, q equal W2 word puppy. M is not, is not anything overtly special. However, m followed by this arrow, which I'm just going to call the Lambda arrow, makes it a lambda expression, which means you're basically defining function like capabilities inside of one statement. All right, So that's a lambda expression. So I could have used an elixir degenerated m, that's fine. But I could have used any letter, any word, any Tolkien and said Tolkien arrow. Then the Tolkien basically represents every record in the database. So instead of me having to use like a for-loop, because we already established not cars is like a list of cards or the list of records in the database. We already looked at how we would have to use for-loops or for-each loops to go through at least to get every records instead of saying get me the cars. And then for each card that is in the database, if the ID matches, basically this is doing all of that logic that I just described for us. So the Tolkien here represents any one record in the database. We get the properties so I can say m dot m dot name, m dot year. So if I needed to search for something, I could use this lambda expression to search by name by ear. In this case, we're searching by ID. The ID that much is the value that is being passed in through the user's browsing attempt to this page. I can see if the car is no because maybe they passed in ID TIN and there's no car with an ID ten, that means nothing would've been flown into the database. So we're saying if nothing was found, then we return the page. There are ways you can refactor this, but I can explain why it was written like this and why would probably want to refactor it won. It was written like this because a database called is expensive. I like to think of them as an expensive thing. You do it when it's necessary at all. Want to just do it off the but just because pretty much what they're saying is that if nothing was provided, Don't wait. A database called, check if anything was provided and if not, then kill it right there. The person is wasting time and resources. Kill it right there. Don't waste the database call. After we do the database call, we still wanted to know was that regard phoned? If it's not found, then we return not found 404. Otherwise we return the pH with the data loaded up online with a create where the Create only had the empty or just the instantiation of car. So there was nothing in card, this was empty. That's why we get the empty form. Because the car dot name would be empty. Car dot year would be empty. It's up to us to fill it and it would get filled and entered into the database on post. However, in the updates were trying to fill this with data before we return to pizza, remember I said that you want to put everything inside of the properties before you send it to the actual appeared before he disputed users. So just like with the index, We're on get. We went ahead and ran the query. So remember that this was being used, this is being used on the page itself, model dot cars. Unlike with the index where we aren't, sorry, just like with the index where we fill the cards with data before we return page. We need to do that for the update. So we need to find the record and then return the page. And then it would automatically bind the existing values coming from the database tool, the input fields on the generated form, which are able to look at in a few seconds. So that is really why it was written like this. If there is no ID provided, don't waste the database, call, killed execution. Otherwise, try to find it. And if you can't find it, kill the execution, otherwise, go ahead and show the page. No, this could be refactored to have one if statement because these two if statements while they're checking for two different scenarios, are really doing the same thing. If we wanted a different response to either one and we have two lines of code to change. Wondering factor could be that, okay, we risk the database call. We try it to find the car regardless, we don't get the value. All right, then I could just say if the car is null, because at the end of the day, if null is passed theory it's going to just see if the ID is equivalent to null, which would never happen. So car would be null, we return not found. Or if that value is 0 or some ID that doesn't exist, Kyra is still going to be null, return, not phoned. You see, I'm just showing you that the generated code, but don't be afraid to explore and modify it, as you may think might be more efficient. But I'm giving you the two scenarios and explaining why one scenario was was set up that way. And what are the pros and cons of it? Now that we have an idea of what the onset is doing and I'm not going to modify this. I'll leave it as it is. No, we can look at what the HTML page has to show us. So the HTML page is going to look pretty much identical or create. At this point, No, you're seeing well there are two the two same forums literally there to see him forms. The difference here would be that degenerated form here. It says update car and I went to change this to edit car. Take out anything it doesn't need. The button by default is save on decreed form. It said create. All right, and then we can once again just take btn block and put it over here. Also, if we didn't want the class for it called MD4, we could meet that called MD, whatever it is. I'm just showing you that the two forms are generally identical between a create and an update form in most web applications, they are generally identical. At this point, you could make another design decision. You could make one page that says maybe upsert, update and inserts that support mental emerge into towards update and insert. And they call it absurd. This absurd Pij would pretty much in the, ETC. Did I get an ID on Get did I get an ID? If I got an ID, tried to find the car and then return to pitch. Otherwise, just load the empty page. That way, if data is presented will show up. If data is not presented on shore up. And then he could do another if statement here to see if the ID is present in shore one value in the button or show the other button called this one is an update button. I would want it to be btn-primary, I'd want it to be T it to be btn danger. So it's orange. I'm just showing you, I'm just, I'm just explaining different design considerations. Everybody has different contexts. And so I might do something that you're seeing, whether I don't need to do it that way. Or you might do something on a colleague or a friend of yours and you see you don't need to do it that way. But contexts should always be the determining factor for your decisions when developing an application. Let us continue. I'm not going to do that absurd stuff, I'll just giving you an idea. But the point is that the forms are almost identical. Same validation rules would be applied. The buck to list is there, we have the button, we have our input fields. I'm just going to rearrange this one. So it looks just like the Create in terms of the order of the fields. But there's one thing I wanted to point out and that is this input for the hidden did change this to all in the last one. For the hidden. If you go back to our Create, there is no hidden. For an ID. This hidden field is absolutely important. One, it's a hidden because our users really don't need to know our primary keys. Think about it. On Amazon, you may see our product number, but that number is rarely ever. The pariah Mary key. You may see an ISBN number for a book or something. You know, an ID number for our students. But that's rarely ever the parietal very key. The primary key is internal to the system. However, it is absolutely necessary for trucking. What happens, because if we don't have that primary key being trucked on this form, then it's always going to assume that this is a new record. All right, so we have to that's why I create doesn't have it because it's always it's always a new record. There is no ID when you're creating something. However, when you're editing or updating the whole thing that we went through the ungulates, it's obvious that the ID is very important. And we have to remember the ID via the form. So that when this person submits the formula, we hit head back to the on post, you see a lot more suddenly in the onboard? Yes, we have validated. We already went through what the validation looks like, that's fine. But then here where we say contexts dot attached car and changes state to modified. What's really happening here is we're seeing database. Please start trucking this object car. So we would have gotten the original car record here. If the name was a zucchini to sport. That's what we got here. The year was 2013, That's what we got. The ID was three. No, don't hear after it has been edited, the idea should never get edited because different IID means it's a different records. So that's why it's hidden and we don't allow the user to see it or interrupt with it, but it's being trucked in the background. Now if I changed it from Suzuki. In sports and in as, oh, it wasn't a sport. Let me take off the sport. Then what we're seeing is database. Please start watching this record and know that it's modified. The database will know that it's modified or Entity Framework will know that it's modified or other because of the ID. So it's going to assume that something on it change. The only thing that should not change is the ID because ID is present, it will know that. Okay. I have a record with that ID, right? No. So what I'll do is save the changes that have been made to that record with that ID. In essence, he's going to end up with two versions. It's going to have the original record that we just retrieved. And then he's going to have this new record or this new version of the record COVID, but potentially different properties. And then Save Changes, we'll say, okay, I'm going to save the new data to the table accordingly. This, in this one, you'll see that we have a try-catch because this is up more delicate situation. Meaning, what if two people were to try and update the car? I clicked edit this car. Seconds before you clicked edit this car, we both have this steel record or at least who both of the current required then I make a change. I changed it from the year 2013 to 2015 and then I'll click Save. You will spend under the longer under record and all your record is steel because you had the version of the record prior to me updating it. When you click Update, you're going to try saving changes. I gained something that was already updated since you clicked it. That would lead to this kind of error or I didn't know about trying and catching from or exception handling, exploiting C-sharp, it we're doing is trying to save the changes, but then it's just sketching explicitly this DB update concurrency exception, which is that very scenario that I just mentioned. They need to seeing that, well, if the car doesn't exist, then return not phone because maybe it was deleted by the time I'm trying to update it. If it doesn't think since then, return not phone, otherwise, just throw an exception and error more Griswold ways to handle this, but that is what the code that was generated is telling us. So that's no problem. However, if the trial was successful, there was nothing caught, then we return the index speech. No, this is just a method car exists that basically just returns true or false. Database check the car stable if there is any record. And here's another lambda expression. And just to show you that the Tolkien really doesn't matter up top is the same lambda expression, but we used m down here. It's the same lambda expression that just uses E. If you wanted to compare them again, just copy this and put it near that. I looked at the fact that they're the same code, just two different lambda Tolkien's. It's basically just saying, Is there any car in the database that has that ID? If yes, then fine. If not, then return. Not phoned. So if it does exist, that means the data is still that I'm trying to change. So does throw an exception, or we could just send button error saying Hey, something went wrong. You probably want to try that operation again. Alright, let us see how this update operation works. So I'm just going to go ahead and jump in. All right, so no, let us look at how this update functionality works. When I click Edit. Notice it's going to bring the data. That shouldn't have been a red button, that should have been btn warning, not be ten dash danger. Let me just make that change. No warning for an orange button. After making that change, I can just refresh. And there we go. No, it's an orange button. So let us see what this editing operation looks like. Notice in the URL you see cars slash update, then the query strings. So remember when we talked about query string called data gets transmitted across forms. So when we use a GET, then are we don't specify it will actually put all the data and query strings that can be dangerous. And while we're working on a static website with nothing particularly dangerous being transmitted from our form to anywhere, it was fine. However, you wouldn't notice that they explicitly generate forms with method equals post, because when you post the data or when you submit the form, you don't want to be sending data across in the query string. Especially like when you're dealing with credit card information or users personal information. Still flight that username and password. You don't want that in the query string I talk. While it's harmless to use the query string for the ID, it may not be harmless when you're submitting from the form. So that is why we always want to make sure that our forms, our method equal to post. However, let's do a little experimentation here. So we're talking on both the hole gets right. So when we navigate to index with the ID, I'm just going to put a breakpoint here again. I'm just going to refresh it when it hits the break point. And we hover over the ID property, you see that ID being passed in. So that is what opened by. We get that ID that's coming in through the query string. And then we're able to determine, okay, Those dot car exist in our system. Now look at what happens when I change this ID to one that does not exist. I only have one car in my system ID. There's no car with the ID TIN. If I tried to bros there, I get ten. All right. And then if I just do F5 and continue, then you would see that it is just saying cannot be phoned HTTP or fluorophore. So this is what we get by virtue of us calling return, not phoned. Alright, so that is basically hold, that works. Now notice once again that this is an on post method. The on post method is what is going to work with the form which is submitting with the method equals post. Alright, so let me go back to the recorded we have Let's make achieved. So the year was 2215, not 2013. That's fine. I went to save and then look at that. 2015. Remember that this is loading from the database every time you hit index, it's querying the database. Whatever you see here is the current state of the record that is in a nutshell. Whole update works. No matter how complicated a system may look, how fancy the buttons and animations and so on. What we're doing here is at the root of every single system, the website that you interact with, all they're doing is allowing you to put data in the database through reform, modified through a form. Look at it through an index page or a details page which we are going to look at in a few or deleted. Eventually. That's all that is really happening, no matter what system you are looking at. When we come back, we'll look at implementing or delete functionality. 12. Add Details Razor Page: Alright, so we're back. And I know in the previous lesson I said that we would work on the Delete, but I have a surprise for the Delete, we're going to do things a bit differently for the Delete. Instead, let's work on our details speech. All right, let's jump over to our code. And I think by now we know the Drew. We're going to scuffle or detail speed. So right-click the cars folder, add Razor page using Entity Framework, we're calling this one details. And the template would be the template for details. Then our model is car and everything else remains. And we get our page for the details with its corresponding code file. Know the details page is pretty much just another page that helps us to conduct to the r from corrode which is read. At this point, it might be kind of difficult to see the relevance of the details page. Because what the details page really shows you is the details of something, whereas the index really shows the lack a preview. So if maybe our table had 20 or 50 different fields, maybe even ten fields, you wouldn't want all of those on the list. Thinkable like a cost, a customer list, or even on Amazon. When you're looking at the products on Amazon, they're not showing you every single thing about the protein. They're showing you the name, their price, maybe how long it would take to ship. But then the moment you click on that product, you then see everything I build a prototype, you see all the potential sizes and colors and where it's from and what material makes it, etc. So that is really what the details page is designed for. In this case, it's arguable that it's optional because car really when it has two details to show at any points which are the ear and the name. Well, once again, if it was a bigger table with more details to show, then you wouldn't want to list all of them out on the index at that point. You probably wouldn't want to show me be the year of the car or the name of the car. So let's say we didn't want to show the year. I'm just going to comment this out. So when you look at the index page, you're only seeing the name of the car. However, you want to see the rest of the details about the car. You click on the details page where they have the link here and then know that we've created the page, we have it wired up. So it's going to go to this details page details that CSS HTML. I will just modify this to say car details. Get rid of that each Doug, there's an old form because once again, it's just reading data, data as an auto-generated link to go over to Edit. So here's another thing. It's looking for, edit out of the box. We use the page name update. So I have to make sure to change that. Then we can go back to the list if we so desire. Alright, so what the details page or the code file is really doing? It has a property car, it doesn't have Bend property clause. There is no foreign present, but does have the property. And then it does the same thing where it says Get me the record with the iodine is looking for that ID. If it's null, return not phoned. It's not null, then it tries to find the record. If you can find the record, It's not phone, return the page. So this is kind of the same code that we saw generated for the, for the edit page. Alright, I'm not going to make the modifications here. These have both to comparison of the regular out of the box scored versus our little modification where we just did a database call and determine if it's not found. So you can compare those, but let us go ahead and run. So I'm just going to Control F5 so that we can look at what the details pH brings us from our index page. If I hit details, then I'm going to see card details and it's going to give me all of the details. So once again, this is generated. You can modify the look and feel of it as you need to. From here I can click it. And because I modified the link, I'm not having a problem jumping over to the edit page. I can go back to list. Once again, all of the navigation is tightly coupled here because every link knows where to find. That's very, very important from any pH, you should be able to navigate to another page. Or null pH should be more than two or three clicks based on the size of a website. But there's generally a tour three click policy when it comes to navigating between pages. That's really it for the details, Nice and simple, compared to all of what we've gone through with the create and edit to see that the details is really just load in the record and showing us. You can modify what is being displayed on the index. Once again, if you don't want all the data on the index page, That's why we have the details page to show what wasn't being shown in the list. When we come back, we're going to look at using some jQuery with our delete. Because with our delete, I'm not going to create the whole page for the delete. You have two ways of looking at it and we'll explore the options when we come back. 13. Add Delete Razor Page: Guys, welcome back. We are going to be looking at working with our delete operational. I started mentioning that there are generally two models that govern hold the delete occurs. One, you can set the behold lead pitch, which is really just like a detailed speech, but it also doubles as a confirmation page because you want to allow the user to see the record they're able to delete and then ask them, Are you sure you want to delete? Let's look at that 1 first. That follows the same pattern we've been following. Go ahead and add a new Razor page using Entity Framework. I'll call this one delete. From the template. I just choose the needs or same model. Then we get our generated page for delete with its code file. So once again, injecting the DB context, we also have a button appropriately for the car. So some form of form or data collection is going to occur here. On Git, we have the same kind of logic that we just saw with the edit. The details page where we get the ID, make sure it's not null, get the record and returned to pH if I record was found. But then on the post, it's also going to verify that the ID is not empty. So notice it is looking for just the ID on Post. It is very possible to just take a parameter that corresponds with the data that is on the page. So let me just run the parallel here. With our update operation. We said buying property on the entire car. Notice there are no parameters in the onPause. That's because the entire car object had fields present on the form. So we had an ID, we had the name, we had the year. So when we click Save, it would actually serialize all of those data points that were entered and place them inside of cars. So that's why I bind properties, basically trucking what data went in to the object, then we can operate on it. Knowing the case of a delete, I really don't need to know the name and the year. I really just need to know what is the ID of the record that needs to be deleted. Then I can specify in the onPause that I am only looking for the ID. Once again, I can do all the checks. Check if it's null. I mean, if I'm trying to delete nothing, then return not folder, but otherwise try to find the car record that needs to be removed. So this time we're just going to use this find async. So it's kind of different from the first-order defaults because the fine these Sing uses the key values so I can disperse into Id as opposed to the first or defaults which requires a condition or this lambda expression, where this is true, then we get a car, whereas the find, he's going to see go to the table and find a record with that ID for the primary key, which of course still runs into the risk of it being no. So we tried to find the car. Would that ID if the car is not equal to no, then we proceed to remove the car database, get the cars table, and remove this record. So we have to find the record. Then we remove the record. Once again, we're augmenting data so we save changes. After all of that, we return to index. So even if Kiara was mode in this case, we're not going to return any not phoned. We're just going to redirect to index goes. Maybe you're trying to delete something that mattered time you click the lead, somebody else, they needed it, no harm, no foul, just return to the index. Once again, this is just generated code. If you want to do something different in your scenarios, feel free to modify it as you need to. This scenario works well because when we go over to the Delete, we see one. It looks just like the details. This is the same code that was on the details page. However, we have a message. Are you sure you want to delete this? I will just do what we always do here where I see top changes are hitting delete car. Are you sure you want to delete this? We showed the details of the car, but look at the form. This time we have a form on all that's in this form. Well, yes, it's method post, but all it has is the hidden for car ID. That is P4 basic analysis. The I Am I am going to bind myself to that property. So you would have seen this ESP form, the Create, see anything the updates, binding to this property car dot ID. But then the name of the property will be ID. And then in the Delete, that will actually just bind it to the parameter ID. So that's how I know that I'm only getting the ID from this form submission. So here we're seeing it's a submit button with the valid delete and it's a BTN dash danger, which makes sense. If you change your mind, you can always go back to list. All right, let's take a look at what we get with the delete. From the list I'm going to click to delete. It's going to load up my record, delete cars, so you want to delete this. And so in the details of the record, we can choose to delete or we can choose to go back to list. So if I click Delete, then it goes back to the list and there's no longer a car in my database or at least the database laws. One less card and it had before I did that operation. I'm just going to create re-create the car quickly. Suzuki Swift sport. And it was a 2013 would and create. Alright, so we have our record again and you can do this for as many records as you need to. So that's option one. You'd want to allow the user to review the record and ask them, Are you sure they couldn't delete and you confirm? Know what if I didn't want to introduce a whole other page just for the delete operation. What if I wanted that right here? When the person clicks delete, I asked them pop up maybe. Are you sure you want to delete? Click yes, and then the deletion happens. Let's try something that no one implementation method of this would be to wrap each delete link in a form and make it a submit button instead of just a URL to the Delete. Yes, we have the page, but let's go back over to our index and kind of modify or what is happening here. I could say form right here. Let me get my spelling right. In this form, we're going to have button. This button basically is going to see the same thing that the current button sees didn't eat. I don't want it to necessarily look like a button. I mean, I guess at this time we can probably start getting creative with our links also. So no problem. I'll just say class equals vt n dash. That's edit. So I'll probably want it to be like a warning. That's it. It button. Of course any button needs to be T and then btn dash the type of button. This is a details, so this would be b2 industry info, just to show the info. And then this button is going to be cost equals b2 and dangerous, No, I user wouldn't be able to tell which one is a button, which one is a link. All of them will look alike. We have this Delete button. What we can do is say onclick. We already looked at that event stuff when we're talking about JavaScript earlier, I can see, Are you sure you want to delete this record? So onclick, I'm going to return a confirm. So that's a method built-in. And when will we looked at the alert method in JavaScript? On-click, confirmed is just another JavaScripts methods I'm seeing unclick return, confirm. Are you sure you want to delete this record? I'm that basically just gives a yes, no box. That is really all I need for the button. But then back to the form one. We want to make sure that it is the method post. Now I'm going to explain why we wanted to be explicit about it being post. There are a number of things happening with the posts. So the implicit benefits of using the posts we already explored, where we've talked about the fact that the data is not being sent across in the URL. It's being hidden in the background. So that's good. I'm inherent protection for sensitive data like username, password, credit card information, etc. That's one. No, you'd probably be wondering, okay, so what since deliverable, maybe the ID. Well, we already saw that in the Delete Forum even then, they tried to use the post here because this same concept, they hit the ID and then we had the delete button. It's the same thing that we're doing except we're doing it inside the list on the index. But then other benefits of the post would be that built into ASP.net Core, our security features against XSS and the CRS if attacks. It essentially without getting into the details of what these two mean and so on. The way they work would be that people can use JavaScript and maliciously hijack data being sent across the wire. What ASP.net has built-in or ASP.net Core. Anytime you have a form and you make it a method post, and then you have that on post waiting for that kind of send across that post submission. They have anti-foreigner Tolkien's validate that any requests coming into a post is valid from the system and not hijacked by an external entity. Alright, so that's like a security feature that's built in. I give I didn't mention that you wouldn't notice that all of that is really happening in the background. So that's why it's important that even though we're not generating or form here, you always want to make sure that you have it as method post and those security features would almost be implied. Other things that we want to do now that we have the form, we have the button, we need to tell it where to go. Now when I say weird to goal, I mean that the other pages that had forums like let's see, the Create they created the form he'd said method post. It didn't have anything explicit to say where it should go. That's because it will assume that once the form is submitted, it's a post request. So automatically it will go to the on post. Otherwise it's going to get same thing with the updates, same thing with the delete index, however, only has one on Get. It has no posts. And we'll know we're putting in a form that is going to be trying to call a post method on the index page that doesn't exist. What we can do now is create custom Handlers. So just buck trucking, just so we understand on get on post. And the one that we're able to create, those are called handlers. These methods getting, posting, doing whatever in the background, they are handlers. That's why we call them. We need to tell the form that it should go to its ISP, P dash page dash handler. I'm going to see DDGT. That's the name of the handler that it should go to. The method is post. No. In addition to that, I also wanted to get the id value. I'm going to see is B dash, wrote dash ID. That isn't me saying that when you're submitting the form, I want you to pass over I wrote value or a query string value with that name. So if I said car ID or if I said pulpy, whatever it is that type there after the word wrote, that is the name of the query string that says the name of the parameter that my handler will be looking for. So I'm going to leave it as car iodine instead of just the ID. Alright, so now you can see explicitly what I mean. So ASP dash route, car ID, it should have the value of at sign item dot ID. Notice every time we clicked Edit or details, it's automatically sent over the ID. That's because from the for-each loop, each item where binding that is p root dash ID here. So that's already happening. We see it happening when you click details. It's called an details page and it's sending over the id value. That is why on Get, it is watching for ID. Just like with details or delete rather on Post, it is looking for ID, and that is because the delete, let me find it quickly in the Delete, we're actually sitting it here. I'm just showing you different flavors. You get the generated code, but it's good to understand how you can do the same thing multiple ways. This works the form and it's sending over the ID this week. This will also work with fewer lines of code, just the form. However, saying go to this page handler and send over a parameter called Car ID with the same ID value. It's a method posts. We're adding that confirmation to the button. And I'm just going to comment out the existing link. But what we're going to do now is create that Delete handler in the index file. In the index code behind. I can extend this and I can say public and not make it an async task. Let's say task action result because I will want it to return an actual results. And I'm going to say on post, delete. We'll look at the syntax on get on post. And I can say post async if I want. That's a naming convention that they recognize. That's optional. But my point is that one I know it's a post method from the forum, so I have to specify on post to I call the delete. I said your handler is deletes. It will automatically look for a handler named delete that is expecting a post response. So just putting on poster on git will tell the handler what kind of requested should be looking for from the Bureau's attempt on post delete. What I'm really going to do is just reuse this code. I'm just going to copy that from the generated delete. Certain things won't adult, but that's fine. We can fill in the blanks, but most importantly it would be the parameters. So I'm going to say int question mark car ID. Why Car ID? Because in my form, the index, I did see that your ASPE root is car ID for everybody else it was ID. What for this one? I'm going to say car ID. I'm not doing it for any special reason. I'm just showing you. What the ASP root really does. If I change the ID, then my handler needs to look for ID. If I changed it to Puppy, it needs to look for puppy. I'm just going to leave it as car ID just so we can see the difference. So car ID from the form, it's going to call the pH 100 delete and it's a post method. So it's going to go over here and look for a handler called delete that is designed for on post responses that's taking up parameter called Car ID, then the code will have to be adjusted because no ID is no longer ID here, it's no car ID, car ID. Now I'd seen that there is no car confident a car, that's fine. I can easily see, give me a local variable called car, because I don't need a property of the class like last time. I just need a local property called car. Go and find the car. Did you find the car? Yes or no? If yes, then remove car. Alright, so this is just my local variable inside the delete. So when you click Delete, we tried to find ID, sir. We tried to determine those. Id have a value. If not not phoned. You probably wouldn't want to do not phone here. If we're deleting directly from the index, then that's fine, That's fine. We can leave it. I mean, once again, context will determine how you want to use a experience to be. So that's fine. We leave it, leave it as this car ID. If you click it, not phoned, try and find the car. If the car is not equal to null, then we remove it and then we reload the index page. Read Erich to *****. Well, that could easily be redirect to page with nothing in it. So it would literally just say, what page am I on? Let me reload that page. We could also say return pitch. That's why I did. I actually results here. So unlike this one, this didn't have a return type. So it didn't need the i action results. But in this case I want to return some form of command to say get me back to the page I'm on. That's why I said task, action result here. Retinol just do the redirect to page without any values. So I'm just showing you the different scenarios. Once you get comfortable, you start writing the code at an expert level, then you'd be like, okay, yeah, I see how everything goes together and hold everything works. Let us take this other Delete or this alternative delete code for a test run. So well it took cars and then okay, we can fix this display issue later on. No problem. Clicked Delete. Here is our prompt. Are you sure you want to delete this record? If we click Okay, it goes, it caused the handler, the delete it read Eric's to the pH. So let's create another one test car. Some random year. I'm going to put a break point. I'm not in debug mode. Let me go over to debug mode and then we can put a breakpoint to see what happens. When I click Delete. I get the prompt click, Okay, then it proceeds to call the handler. So once again, it knew where to look because I told the form, use that particular method and pass over that particular route ID. And this is the method request, the method to be used. All three of these combine to let the form null that wants it is submitted. It should hit this handler and the coding side of this handler, the name suggests it's, it's a, a 100 supposed to handle this scenario. This scenario is I want to delete this car, car IDs three, alright, so we see that the route ID is going over. Well, obviously it phoned the car in the database or it will find the current database, remove it, and then redirect to the page it's on. So let me just hit F5 and you see you just read Eric's without any hustle. Alright, so I just quickly fixed the display is you are having here with the buttons. And it's a really simple fix. Probability, even a HUC, depending on how you look at it. But instead of putting the anchor tags old side, I just put everything in the form because the form is what was breaking the lines. So I just put the anchor tags inside the form and that's really to know consequences because at the end of the day, only the button will do the submission. If I click on Edit, it will just navigate away. If I click on Details, it navigates away. Then if I click on Delete, I get prompted effectively cancelled. Nothing happens. And then if I click Okay, we've seen what happens. This is hole. You can start working a little JavaScript in node to start seeing, okay, well, this is what it's supposed to do. When we come back, I'm going to show you a little more JavaScript. I will start styling up our pages because we see our Create button is up top. It looks like a link. We started looking at total to style the Edit button, the button list is still a link. The details has two links. So when we come back, we'll look at more robust confirmation prompt. We're going to be using this library called Sweet alerts. That's one. And how we can use JavaScript or jQuery to get that in. And two will start styling up RPGs a bit more. 14. Using Partial Views and UI Enhancements: All right, welcome back. So our objective for this lesson is to one style all of our links to look a bit more friendly. And what we want to do is put in a bit more robust confirmation on the delete at the very least. Let's get started. Firstly, let's create the change and create link. Let me jump out of debug mode, go over to my index.html file, and here's the Create button. So we saw that all we have to do for our anchor tags is give them the class BTN dash. I'm primary for the Create. Let's get a bit more creative there times when you may want to think about putting the icons right? So sometimes you don't want the whole word edit or the whole word details. And you can even remove these pipe icons a bit. Or even like the Create you'd probably want and it's a plus sign on its soul. What we can use for that would be Font Awesome, which is a library that has a number of icons. And we can look at it quickly. If you jump over to Font Awesome.com and we're looking at the icons in version 4.7, you'll see that you have quite a few icons that you can use. Most of them are free. You may have to pay or enrolled in some account that they have, but that's fine. But right now, there are so many icons that you get out of the box that it is really cool. So if you want an a plus sign, I'm sure to have a Pelosi use of plus. I think they have like a bean or rubbish or something to signify delete. But they have quite a few icons that we can use in order to just display certain things. There we go, trash. So sometimes you want an icon. Now what do you think you might be? It's called something else, but No problem. Let's see how we can integrate this into our project. Back to our code. We can right-click dub, dub, dub root folder. And then we can add a client side library. When we do that, we just have to type in font. Also many seats already kind of filling owed for us. So Font, Awesome, icon picker. And then that's not the 101. It's not an icon peaker. Let me try again. So I'm just removing the target location. Let me actually just counsel and start again. So add client-side library. I'll just type font, and there it is, font hyphen, Awesome. That's what I want. When we click that you'll see is going to tell those that we're going to be putting it in the target location of dub, dub, dub route slash font. Awesome. But I like to have all of my third party libraries are organized in the same place. So instead I'm going to say dub, dub, dub route slash, LIB slash Font. Awesome, That's where I want. But these are all the files that we'll be getting. And I'm not going to modify any of that. I'm going to choose specific files. I'm just going to go ahead and hit Install. And then it will download the required for me and add it to the folder that I specify. There it is, Font Awesome. We also got an additional file in the form of this Lindeman dot JSON, which is basically just striking to say these are the libraries that you have used the client library manager to Install. Alright, that looks good so far. Know what I need to do is let the whole layout know that it should also include Font Awesome resources. In the head area where I put all my style sheets right above the bootstrap. I went to put in the style sheet for the font. Also. Where am I getting this style sheet? It's in the lib folder, Font Awesome folder, CSS folder. And then you'll see all all dot Min is kind of collapse on the debt. So instead of using the all we use the minified version. We already discussed the difference between the one version and the minified, right, so we'll just do that. So we include that file right there. With that inclusion, I can No, go ahead and look at how I can use my icons. If I jump back over to the website and I look at the examples, then it will show me what the syntax looks like and it's really simple. All we need is an I tag and then a class with FA. And then if a dash, whatever icon it is that we're looking for. We did say that we wanted like a trash for the delete. On. Here's a practical example. You have the anchor tag, and they didn't set up the anchor tag, you have that icon. Then whatever takes the one, that's where you get that host icon beside home. That book we said library, etc. So you can be very creative and use these icons as you see fit. So here is something practical we see here we have the bin. How do I get the bin? Okay, It's trash. So I'm going to just borrow this. Jump over to our code. Then in the delete button instead of the word delete, I only want the icon for the trash. For edit. Maybe I only want and let me see what the testimony. So I think if I'm not mistaken, the intelligence will actually start filling out or options based on the fact that we included the CSS. What if I wanted a book for edit? Let me see if there's an edit. Edit. There's one explicitly for edit. And then for details we can probably use something like let me see if there's something for details. No, then we can use bulk or an old book dash Open. There we go. Sometimes you can, you would have to sit down and explore the different icon ideas or the options rather. And then you come up with your own based on what you want to convey to the user. So I'm just going to quickly preview this. When we take a look, we see that, okay, this looks like an edit. This is an open book. I hold. My user would infer that this is the details look at more and then the trash icon is not showing up. So if I jump back over, sometimes also based on the version of the font Awesome file you're using certain fields are certain classes might not work. So like trash dot dash or might not work but dashed trash my work. So let me just made that change refresh. And there we go. So we're getting our trash bin looking much better. I'm just showing you that these are ways you can use to spice up how will your displays are if you don't want to rely on just the icons, because not everybody might just infer what we want them to from just the icons and you can always edit text icon then the word edit details and delete. Let it not be said that it wasn't very user-friendly because you didn't know what the icons MIT Boulder least it brings that little flair to it. So even for the Create button, the create link, rather I'm just going to copy that I tag. And then this is creating a new bot. Then up top, I'm going to see is there a plus sign? There is a plus sign. So if a dash plus refresh, and we see that plus sign up periods. So that's how you can start to bring out the corrupter to your display of your application using these third-party libraries. You can go through. Challenge you to redesign these pages, put on me at the buck to list a bit more robust in the details. She is the editor and the buck to list here and we'll need is already doing what it needs to do. You can go ahead and do that. So I hope you took on that challenge and that you went ahead and applied some creativity to the other pages. But I'm going to show you what I did. And so we can compare notes on the edit. All I did was to add this back to list. Now notice that this above two list is, it is a beaten with a primary coil or both. It's only has that look when I hover over it. That was easily accomplished by using BTA and dash line, dash primary. For all the pages that had the buck to list the link down at the bottom, what I did was move it out of the DV was in, put it in the same div as the Submit button, and then give it the btn, btn outline primary. And everything else remained intact, but I gave it left arrow icon. Even then, missed an opportunity here with the input. So the input not put in that icon. In the input. The save button is just an input is not a button tag, it's just an input tag. If I wanted to put in something to say it's saved and I couldn't use the input. What I would have to do is use the button. I came to show you what I did and I'm noticing that if I had more room for improvements so I can meet that button and give you the class btn, btn dash warning. And then buttons can take a type. And this one would be a Submit button. That's fine. But then for its icon, Let's see what icon I could use here. If it, is there a Save, okay, if I save and I think that's going to give us that floppy, this looking icon. So after making those changes, I end up with that save button versus the inputs. So I'm just showing you how you can use different tags to accomplish the same functionality. So now I can remove that input tag or that input. Yes and no. I only have this save with icon or above to list. Once again, that little hover animation is accomplished just by missing BTN, outline dash, and then you have the same primary warning, danger, etc. I was in a process. I'll see you in that every page that had the buck to list link, all I did was move it into the same form group as the button for the submission. So that's the update page on the Create. I did the same thing so I can meet the same kind of modification here with the Create button. I'm just going to do that while we're all here looking. Taken that button and this is almost as straightforward copy NPS will only difference would be that this would be primary. Or I can make it something else like success because it's a Create, so it's success, create. And then it can have the save icon also. I could see if there's something else I could use. I can't think of anything else this moment, so I'll just leave it with the Save, the Create Page. Clip up to list two and I click Create New, I get that green button. That buck to list. Okay, then for my details page where I had the edit and back to List same principles. So this is the same button coming from the index page for the Edit. And then this is the same bucket list that we have been using. No, there's a little syntactical difference in the details speech where the ASP dash route ID of course is model.py car dot ID. So that's one difference between what would've been and what I had to type what was on the index page rather versus what has to be on this page. Otherwise. Now we're starting to see how we can add a little, once again character to our application. Now that we know how to integrate third-party libraries, the last thing we're going to do is use sweet alerts to handle the confirmation for the Delete instead of the standard Java script prompt that we are currently using. Step number one, let us find our sweet alerts Library. Right-click www root again, add client-side library. And I'm just going to type sweet alerts there it is popping up. I'm just going to go ahead and include that. And then I'm once again changing the location. I wanted to dub, dub, dub or root slash lib slash sweet alert. Go ahead and hit Install. It will update or library manager or a lib man file. So now we know which additional library has been added, but we also get the files or the file added to the project. Know that that is in place. Let's jump over to our layout file and include the script. So the reason we're going to include it in the layout and not in the page or the, you know, exactly where that if we want it in multiple places, then you would have to repeat that inclusion everywhere, which I don't necessarily want. So I'm just going to include the threat above the site GIS. I will just add that script tag where the SRC is equal to. I will know it's in the lib slash seats alert slash. All of that was below by intelligence. Nice and clean. That is, no, we can access that sweet alert library from anywhere in our application. You may want it on different pages. When you have different index files, you want to have the same kind of delete functionality. You can, you can do it everywhere. When I go back over to my index page, I need to set up a section for a scripts. Now, this is something that we already saw because on our Create page, it was their section for scripts. So let me give you a background as to what this section is I can highlight it at. Okay, we wanted to include the scripts and so on, but I didn't quite explain why the section is there and we didn't just include the scripts. Going back to our allele old page, you'd notice that you have different sections, so you have the view datatype. We already established what that is for. We also have the render body. We already established that that is where all of the content inside of our views, it will get rendered inside of the entire layout later, don't, you will see that you also have a section that says render section called scripts, and it is not required. This allows that whenever we want to put in a script, we can invoke that section, putting that custom JavaScript jQuery script or whatever it is. And when the page on a whole renders, that script area would be rendered underneath everything else or relative to his position in the Leo piece, that's where it will be rendered. This is important because remember I talk about dependencies. Jquery, then, then bootstrap has a dependency on jQuery. That means I can't put the bootstrap inclusion or scripture reference above jQuery because then what Bootstrap needs to do will not be available because jQuery was not available. Just like with the sweet alert. I can't call it a sweet alert if I don't have the sweet alert library already available by the time I'm writing my code. While we need to do is make sure that we have all of our scripts that are needed across the board, all in our layout and then in our views whenever we need a script or custom referenced another script, we make sure it puts it into section. Going back to one of the existing forums, the reasonably at to do the validation scripts is that validation scripts are both jQuery related libraries. We'll be calling JQuery functionality before the jQuery file exists. It puts it in this section so that when the whole layout page gets rendered with all of the scripts and the novel and so on. Jquery is on the page already. So by the time the form loads, the jQuery validation scripts are loading after the jQuery. In our case, we want to make sure that we call our sweet alert code after the sweet alert libraries aren't in a pitch at science section that I went to. See, I wanted to scripts section open and close. Then in here I can start writing my own custom JavaScript or jQuery or whatever I want. In this situation, I need a jQuery event to watch for when the form is being submitted. All right, So let's read this together. Let's see if it's going to work, but I'm just going to walk you through what I'm doing and we can fix it as we go along. So dollar sign, we're using jQuery. So once again, I can't be using jQuery code until the jQuery library already exists and has been invoked. I'm just going to C dollar sign. Put in that function dot global function open and close, brace semicolon. And then inside of this function or I can start writing my custom code. So dollar sign, and I'm looking for a form submission. So I'm just going to say form submit. So on a form submission, we want the phone Shun. And I went to give you two a parameter called E. So E is just like an event argument to see, well, I represent the event that's about to happen. So you're trying to submit the form. E has the information for everything that's about to happen. The first thing I wanted to do is tell it E dot prevent default because the default operation of a form submission is to submit. I wanted to pause that because I'm about to ask, Are you sure? All right. So the button remember we're pleasing this unclicked stuff with the sweet alerts. So you click the button, I want to pause the default behavior of the form submission. And then I'm going to see swale, which is my sweet alerts, while is short for sweet alerts. Instead of that open braces. And then I'm going to, just, in JavaScript's, the code hinting is not as powerful as HTML and CSS and C-sharp. So what I tried to do is when I open something that closes same time and put the semicolon, so I don't forget it later on. Swale takes a few arguments and if you want, you can look up the sweet alert documentation. It's always good to look at the document is. So when you're not sure, but for now I'll just continue and we'll just look at it here. So I went to see, are you sure? This is the title of the prompt? Como? Then we have the text, which will be the actual message that the person is going to see, which is what I'm going to see as what we had before. Are you sure you want to delete this record? Going to see icon. Icon is warning, so it knows that this is a very serious moment. I'm going to say buttons equals to true. So sweet alerts really can just be like a pop-up to say, okay, this happened. You click it off and say, okay, when you say buttons, however, by default is going to give you the archaea and cancel kind of prompt like what we saw with the onclick. Then we also see a danger mode is true. Notice each line ends with a comma because this is like a building or to the whole object. Note that we have the sweet alert object Bill told we need to continue to see. Then. The then part is going to be like a delegate notes to see, watch for the input from the user. The inputs will be stored in whatever variable we put in. So confirm. I'm seeing then watch for it to confirm. If I click Okay. Confirm is true. If I click, Cancel then confirmed his false. That's pretty much what it is. And we do that same kind of lambda expression into this. So this is a delegate function where we're just making a function on the fly to see then carry on dysfunction against the variable confirm. I'm seeing if confirm. What do we want to do if confirmed. So if confirm is basically seeing if this value is true, if they said, Okay, then what do we want to do? What do I want to do? If they said they confirm, then I wanted to say this dot submit. I'm pausing the default behavior, but then I'm seeing, okay, well, go ahead and submit. If they said yes, let us state this for a spin. All right, so I've gone ahead and added some additional records so we can test. So I'm just going to say delete and oh, snap, I didn't remove the original prompt, but let me just click OK and continue. And then you see here's our suites alert. Look, oh, nice. That looks. Are you sure that nice little icon? Just let you know that hey, danger ahead. Are you sure you want to delete this record? If I click Okay. Okay, It's still a prompting, so we have to put it in a bit more funness so I know exactly what's happening. What's happening is that because each one of these delete buttons is a form. When you click Delete, it is seeing all of the forms, the page. And then that's why that prompt is coming up multiple times. So no problem, we're exploring what needs to go in place to make this thing work properly. So firstly, neighbor move this onclick. Now that we have the sweet alerts, we don't need that browser defaults prompt. We know have a nice cleaner interface to use an alternative method to printing up form per lecture that I see printing off form for every single button would be tough one form. And then we'll watch on the button, please. I'm just I'm just showing you all of your options. So we saw that this works the default prompt, and if you're comfortable with that, no problem. But then sometimes when you start working in other libraries, starts having to make compromises along the way with your entire design. Alright. Lets us work on combining our knowledge of how forms work on hold the posting works on all the data needs to be sit before the submission can occur. What I want to do is create one instance of the farm instead of having three records and three different forums, I want to have yes, mini delete buttons as many Delete button says, there are records, but we're going to use one form to execute the delete a command. I'm going to take this form and I'm going to place it underneath the table by itself. So I'm just cutting the form tags and putting them by themselves. I went to remove this is b root car ID. And instead I'm going to give it an input, just like what we saw in the origin or delete. In the originality lead form. We had one form at the bottom of the pitch. We had that hidden, so I'm just going to copy that so that we have a point of reference. Input type is hidden, is before we don't have any property or anything in the model called car. I can't see a card auto ID for the ASP for instead, I am just going to give it a name. The name here is car ID. Now, what is the relevance of name? When we have a form? Any form? Remember that when we did the basic HTML page, we talked doubled the name and because of the name, you saw the stuff going across in the URL. It's the same principle except ASP dash four takes care of name and ID for o. So you'll notice that our input tags here, we didn't have to see knee would be enough to see it ID all we have to see it as inputs and set the class and the ASP dash for bone did tool, the property name for the model name would be the replacement for ASP dash four. So really and truly what gets printed out is id equals Car dot name, name equals Car dot name. We can manually give our own tag, its own name, which would correspond with the same route ID that we had or the same route parameter that the post method is actually waiting to see car ID here. Car ideas and I'm also going to give you the id, car ID so that we can access it through the jQuery. So that is our form. It doesn't even need a submit button because we have the button here. We do, however, need to know the ID of the button being clicked. So I'm just going to add another data attribute. Once again, we're just exploring all of the compromises and all the nice cool things that we can put in. There is an attribute that we can put onto the button called data dash ID. And then we can give you the same value of item, dot ID. Know the links have their IDs and each button that is going to be doubling as a submit button will have its own ID. No, we need to watch for a button click instead of a form clique. For that, I can easily say, give this a custom class, delete btn. So every delete button will be identified as delete btn inside of my jQuery. Instead of watching for an entire form submission, I can know say Dot Delete btn. So watch for a click event on any element that has the class delete btn. So you see how that's going to all come together. Whenever that is clicked, there is no default. I don't have to prevent defaults, so I'm just going to remove that. Showing you once again context. Why do we write the code on the different circumstances? So there's no form for it to submit. I don't have to prevent the default behavior from a delete btn click. However, what I do need to do is prompt, which is still going to happen. Then if they confirm, what I'm going to do is and I have to give this an ID so that I can identify it. So anytime we need to identify an element in JavaScript or jQuery, we can use the class or we can use the ID. So this is delete form. I'm going to see one that the value that the input should get should come from the data ID of the button that was clicked. So let me just do all of this step-by-step. Firstly, let's get the buttons. So I can say var btn is equal to dollar sign. This. This is me saying that this is the element. This is an object that represents whatever elements triggered the event. That's step number one, tool. Var id is equal to and then I can get the ID from the btn dot data. The reason I used data dash IDs that indeed query you can easily bind to that data element and get that key. Get the value based on the key. I'm seeing btn dot data, and then get me the value that is being stored with the key ID. And now we have the ID or car ID that corresponds with a button that was clicked. Know after I have all of that, I went to set the value of the hidden elements. So dollar sign quotation marks, hashtag and its car ID dot val. And then I'm just going to give you the ID. Know the value of this hidden will be set to whatever ID was on the delete button. Then after doing all of that, I can now see dollar sign hashtag, delete form. You use the hashtag for ID just like with css, dot full class hashtag or pound or the number saying for IDs. So I'm going to go for the delete form by ID until it to go ahead and submit. Go ahead and carry out your default behavior after I've set up your data for you. So let us state this one, this version of it for a spin. We can click, Delete, we get our prompt, we click Okay, and look at that. It's working, right? So all that we did was in the background. Once again, we created a form tag. So even if you inspect element, you notice that at the bottom of the table. So we have body and let me go into the div, that's a container. And then we have the table and then we have our form C. It's not differentiating on the page. It doesn't seem we were in conspicuous when it was attached to every button, but no, it's only one form on the page, so there's no confusion as to which form is being clicked, which button which for me is trying to be submitted. There is no confusion anymore. There's only one form. And then if you look at each button, you'd see that the data dash ID has the ID corresponding with all the other links. So this is ID five. When it is clicked, we get the button that was clicked. We get the id. Then we set that to the hidden element. Then we go ahead and submit. And then the form knows that it should go to the Delete handler with a method of posts and it's passing over that hidden value called Car ID. Once all of that is in place, you will hit the on post delete with the route ID to expect. And what we know it's supposed to do all of that, all of those enhancements whenever we're putting in third-party libraries and wants to use them, you know, we have to take those kinds of design decisions as we go along because you may think it will work or it may work in a particular situation. But then when you add other code and libraries, you might have to add some more funness. Just modify your code refactor as you go along. So that's it for this activity. See you in the next lesson. 15. Add Changes To GitHub: All right guys, welcome back. This lesson is going to be short. All we're going to be doing in this one is checking in order changes. So we started using GitHub some time know. And what we did was to check in our initial, when we got to a certain milestone, we checked in all of our changes. We wanted to do that again. Red ticks indicate files that are pending, changes or edits. The green plusses represents the ones that have been changed and the blue padlocks basically represent ones that have not changed. All we have to do is go to get changes. Once again, if you don't see where it is on my screen, you can always go to View and click Get changes. Then that packet will show you every single file that has been added solo for third-party libraries that we added are all there. And our migration file and or entity files. So I'm just going to give a quick message. While the message doesn't need to be an essay, I usually like to be as descriptive as possible in my message so that anybody reading it will get the gist of what I am doing in this version, commit. After doing that, I can just say commit all and sink. Once that gamete has been successfully completed, you'll see that message. And then when we go back to the Solution Explorer, everything would have blue padlocks. When we come back, we'll start extending our application a bit more. 16. Manage Database Changes using Entity Framework: In this lesson, we're going to be setting up our other entities for this application. So right now what we have is car, which is essential. Both all we have for car would be the year and the name of the car. Know if you've been around cars long enough, you know that it's not just a name cards have a combination of a meek and a model, right? So the meek would be the brand of the car like Nissan or Lamborghini. And the model would be modeled off that make, are we dealing with? What we want to do is make some database changes here. And what we have to sacrifice is name and split it out into make and model. At this point, you wanted to make some design considerations because it's easy enough to see. Okay, I wanted to change this to me and we'll just duplicate that and meet that model. And it will be easy enough to just have string. But then consider this, when somebody's entering a car into your system, do you necessarily want them to be typing in the milk and typing in the model? What if you have two of the same kind of Mecca and model vehicles? What do you want them to be typing in the word Suzuki every time? Because then maybe the leave vote or the mistake, one of the SAT scores it or vice versa. The point is that At that point you want to limit the possibility of human error when taking data through our user interface. While this is not a user interface decision, what we do here will influence how we design or user interface. So generally speaking, in a form when there is data that needs to repeat, you'd use a drop-down list, meaning that you would have a drop-down list with all of the potential options. You wouldn't leave it up to the regular user to be able to just say, oh, here is the value and just type it in manually. For me can model, I feel more comfortable or at least for MEK, which would be the brands because that's more acidic than the model because different brands of different models and combinations 0 so they can type in the model, but for the mic, personally, a few more comfortable giving them a list of the potential brands. If it's not in the list, we can add it to the list, but it's better they have that list. And they can type in the model relative to what they chose from the list. That's going to force us to make some key database changes. Because if I need a list of mic, I can't be seeing string meet. Now what we're going to start talking about what we call foreign keys and primary keys. So we already know are both primary key. All right, but now we need another table and we need a foreign key for that table presents in car. So let's create this new table. So migrations, sorry, nothing migrations in the data project rather, I went to add a new class, and I'm going to call this class me the mic. Remember that these, these glasses are just models for what a table with have a tail will be scheduled on the properties for what we wanted to store our voltage. So what would we want to store both the meek? Firstly, we always have our public int id. Then we would have the name prop, top tub, string names. Name here just means name as in the string value that goes for the mean in table called mic. Make number one could be Nissan, make number two could be Toyota, etc. So that's really what the name here represents. If you wanted to go and say Make me personally, I don't follow that naming convention. Some people do. I don't because I'm already in the table called mic, so I don't need to see me name obviously, name would be the name of whatever value I'm putting in that table right? Now we have the main table, It's fine. I have to let the database contexts know that there's a new table in tone. I just went to that line Control D just to duplicate the hard parts. But I went to call this mix. I could also call this car makes it doesn't really matter what I call the table. But I really like to be consistent with the name of the entity and the name of the table, as you don't see him with car and cars. But once again, you may not necessarily like my naming convention and you want, although one, then, no problem if you wanted to name this car mic and car mix or you have the entity called Mika, this called car mixed and that's fine. I like to keep them consistent because it leads to fewer errors down the line. Now we have a new table. What I need to do is let carnal that it should be a four or it should have a foreign key to make. Entity Framework makes foreign keys very easy for us. What I'm going to do is okay, I'll leave this validation message for the model. That's fine. But underneath all of this, I'm going to put another property, int make ID. I was making the point that Entity Framework, it makes it easier for us to introduce foreign keys. Because when we say we want a table name and ID, it will automatically infer that we mean we want an, a foreign key. So that's step one, at least. It does by saying int mic ID, it will know that, okay, I have an entity called Mek, and it does have an ID, so the combination means that there must be a foreign key. Another part to this though, is to add our navigation properties. So we would say Make me this navigation property basically says that if I get a car and I wanted to know the mic off the car, make names are really stored in the make table. So all I really have to go off is that ABA car and it has make ID1. I don't know what the name of it is, just from the car table. All right. So if you're used to databases, you would know what I mean when you look in the car table or when they are foreign keys, all you're seeing are the ID values may cause ID1, then car off mic ID1. It already go into C's make ID. We don't know the details. So by adding this property and generally speaking, we add it as a virtual so it can be overridden if necessary. So you can just go ahead and do that. But when we add this navigation property, when I retrieve a car, I can say please also include all the details of that additional table or that related table. Then I can bring the mic property with all of the details. Whatever details went into me, maybe I couldn't even put in something to see which country the mic is. Say if I wanted to get creative, I would say this make is from this country. And then I would run into the same kind of data quality issue here if I leave country willy-nilly, because something from United States of America could be written as US by one bursa, USC as another person, United States band on the person, etc. So that is why anytime you have something that you want to control, you'll want to put it in its own table and then make a foreign key reference to it. I'm not going to get too complicated just yet. Let us look at having two tables and we're introducing this foreign key concept. At this point, car knows that it should have a foreign key to the table where the navigation or asserted the validation of models. So it's required. I'm also going to require that the ID is in is entered year. We can require a year if we want. We could also sit more validation on these two syringe. Minimum, minimum for the year. Let's say we don't want anything less than 1990s in the systems. Anything that is 191990 or before 1990 is not applicable. And then maximum Let's just put it to 2021. We're in the year 2021. So I'm just showing you the range. Validation really works. Let me space the mosaic can see everything in its own space. Remember that all of these annotations, all of these things need to fake the database to affect the database step number one, or after making those changes, the next step would be to add a migration. I still have my migration commands from the last migration or the last set of database related activities. We did remember a city, a default project to the data project. And he can press up to get the previous commands. I'm just pressing up to get the add migration. I'll just change a misses. So I did mix table, press Enter and my build field. Why did I why did my build fail? Well, that is because I deleted name and name was being used very much in other parts of my application. If you're encoding during this, this is one of those consequences of refactoring on application Ricci and something that you might have a ripple effect throughout the rest of your application. So let's keep this simple. Firstly, we instituted the delete form and so on. So I really don't need the Delete View and this delete dot CSS HTML. So what I'm going to do is just delete this, delete, delete fuel. I don't need that one. Fine for the create. What's I'd have to do is just at least temporarily comment the zone. So anywhere that the name property was being accessed in any of your views, you can just go ahead and find it. It was being used here, come into totes, coming into totals here. So no, Unless it will show up in the list. The update was also being used here in the form that you can just double-check your error list just to see where you might have missed. And I'm going to do Control Shift and B to do a built just for it to recompile and see if an error is are there and there are none. So let us try it out with Package Manager console again. In audibility successful and we have our migration. What's in our migration one is going to rename the column from name to model. All right, so just because we changed the property is going to see it as I rename as opposed to delete. All right, for our Meek ID seats adding the column, it's an int. It's not an available, and the default value is 0. Even though we would've sit three inch to be in 19192021. So that means even then, it should never get this fire where the database would have to set the default value to 0 because the client said we'll always do the validation. We saw that happened already. Then it's going to create a table called mix with two new columns, giving it the primary key. And then look at this part. It's creating an index. An index in a database is a high-speed lookup. So whenever we look forward to cars using the make ideas are key or we're using that to say, give me all cars with this unique ID. By creating this index on that column, it will do it very quickly. We're also adding the foreign key constraint. It says add a foreign key in the table cars, the column mic ID where the main table is mix and the principle of columns ID. So in other words, a foreign key means that make ID in the car stable can never get a value that is not available in the mix table. I can't be adding a car that is not of type or not in the mixed mixed table. If it's in the mixed table, I found you have three icon. Add a car with ID TIN. I kind of just putting a car that's not present. So that's kind of protection. So you call that data integrity when you're talking about database design one and to maintaining that integrity through your application design. So between all of these and validations, that data integrity will be upheld. Once again, the dome method is basically the teardown. So if we have to undo the migration, this is what it will do to repeal the changes that would have made. And after doing all of that, let us go back and update the database. So this run-up bit database and the Package Manager console, nowhere seeing some arrows are no problems. So let us read through these arrows. It is seeing that it failed to execute the Alter command where it's adding the reference to the foreign key mix table. So it's in that mix has a column ID. And in a nutshell, without, the thing is that these arrows tend to look very complicated. The wording, if you're not used to, it, might not come off as very user-friendly. But the reality is that if you just pay attention, you will pick out certain keywords. Right here. It's saying that the altitude was Stephen conflict over the foreign key constraints on the column that we're trained to add, which is mixed with Meek ID rather. So what's the problem? The problem, even though the areas that are really seeing that, hey, this is the problem. If we go to the database and look in the cars table, remember that we had entered some cars. He had entered cars into our database in or they don't have the mic idea what they are there. And the mic ID cannot be 0 because once again, the mic ID cannot be a value that doesn't exist in the mic table. This is one of those dangers when you're changing databases are doing migrations. I'm going to have to make a modification. And there are two ways to make a modification whenever you're introducing a foreign key into a table that already has data, one of the dangers is that you're going to end up with this error. This is one of those good Aras, I call this a good error to learn from. This conflict is because I'm introducing a foreign key into a table that already has rules that didn't need the foreign key. As far as it's concerned, those existing roles, roles are violating the constraints that the foreign key is being told it should have. The foreign key column is being told it cannot be null and its default value is 001041. Sorry, He's an invalid value for our foreign key. Why? Because you cannot have. A primary key are matching primary key value of 0. So Meek ID can never are in the make table. They can never be a value of 0. It always has to be one or above. It can never be 0 by trying to enter IT pro, reactively into the database or after the fact that there are already rows, it is trying to give them the default value is 0, which is causing that conflict that it is talking about. All right, I can actually modify the migration file here. Or I can remove the migration, changed the model, and fix the error. So I'm going to just show you what modifications I would make to the migration. And that would be to change the knowledgeable from false to true. So in other words, this can go in, the foreign key, can go in, but it doesn't necessarily have to have a model. The existing cars will just not know what model they are. Pretty much there would be no. That's why nobody is true. Then I don't have to sit at default value either because it can be known. So if there's no value, then it's no. If there is a value, then there's a volume. That's option a. Option B, it would be option E. Let me before I continue. Option a, would allow me know to actually just try the update database again. And then it would try new and edited migration operation, which would be to add this column as nullable. And those remove any potential for conflicts. So that's one of the options when it comes to having migration generated. That doesn't necessarily meet the requirements are you need to modify this, modify the migration, and try again. No, another option would be, and I would probably choose this option because it's a safer option in my book. One, remove the migration. So just see, alright, forget that I told you to do this migration. To do that, It's literally remove hyphen migration. I always saw this command earlier when we did the ad migration and it said to undo this action user move migration. We have a migration that's quality. We want to undo it. So I just see remove migration. It will actually delete that file from the migration folder. Then I went to update my model to then have rules that will generate a bitter migration. The rule that I went to modify is I went to make the mic ID nullable. Another thing that is influencing the Entity Framework decision to make this an int that is not nullable is our notation to say it's required. This is going to be a perfect segue into how we are going to have to separate the validation at the database level from the validation at a client-side level because at this point I'm seeing required for the year and sitting area and Joe K, that's not really going to affect that a database. But then we saw where the streamlined is being reflected in the database and the fact that model is not nullable is being reflected in a database. Then when I made this nullable on the user interface, I'm going to need it definitely, I'm not going to upload them to proceed with the voltage. However, at the database of them saying it's optional, those are separating into two different worlds. The UI needs are different from the database needs. Just keep that in mind. But we will be finishing that concept in short. After removing the required annotation and making the int and int, I can know go ahead and rerun my migration. And when I do that, my migration is not seeing for the column, it is int, but it is in nullable. No default value. That's no problem. Everything else is fine. So when we go ahead and update our database center, then it is successful. You'll see once again, analysis has to go into what might be causing the problem as much as the error didn't really hint at it. But that's one of those areas that generally speaking, if you see that error, does look out for what might be the potential risks are ruined me introducing a foreign key at this point in my database design, because this is going to be an ongoing activity. As you see something new, you're going to have to edit it. Well, it's this easy to just generate. A migration will be at the database, but then it becomes more difficult because of the rules and the constraints being put in around the different columns versus the existing data which might not have known about the rules at the time it was being input. That is us introducing this new table that assist jump over and you'll see that we have the table and the car stable. If I extend this, you'll see that in the keys for the cars, I have the foreign key that was just introduced. If you look at the name here versus the name on my line 39, you'll see it's the same name. If gay underscore cars on the score mix on the score Meek ID, that's the name of the foreign key. If we look up mix, we will see also that it has its primary key. So no or columns for cars would be the idea which is a primary key int year model. And then make Idea notice that key Item I can't beside it, which means it's a foreign keys, primary keys. Foreign keys look like that. We have successfully added another table to our database. We also had to compromise and remove some of the things from our user interface, the facilitated. When we come back, we're going to have to update our user interface to normal the new field. Fields because we no longer name we know our model and we have mic. And we're also went out to look at how we are going to separate the rules around what users can do on the user interface versus the rules that database is imposing. 17. Form Enhancements - Part 1: All right guys, we're moving on nicely. When we were last year, we set up the new tape before mix will also set up the foreign key association for mics on cars. Know the rules that we followed could've been extended for any number of foreign keys because some people would have extended antidote kit. They won't models steel because they can't risk to people writing the word Sony for the same Nissan, nissan Sony. And one person puts in one in, the other person puts in two ends. Later on we'll look at that kind of scenario board right now we wanted to focus on getting our user interface updated with our introduction of our new fields in the forms of makes and models or Meek ID and model. The first thing or well, I don't want to say first thing as though we need to necessarily follow this order. But one thing that we are definitely going to need would be the crowd pages for the mean. Because we can write no, cars has a dependency on Meek ID. I can't very well putting a drop-down list for the mic instead of the cars unless mix exist. I'm going to have to create some pages so that we can manage the mix. I'm just going to go ahead and hit add a new folder. And I'm going to call this mix. Then last than we actually went one-by-one creating all of the code pages. We did the Create page, so we did the edit page, etc. For me, I went to do a more wholesale operation. So we're just going to right-click this folder, click Add series of page, and then we'll use the option Razor pages using Entity Framework and crude. Alright, click Add. Then he's going to say, okay, what is the modal class this time we're dealing with mic, that is the data context and click Add. Now if you take a look at what's in the folder, you'll see that all of the pages that we saw meticulously added one by one when we're dealing with cars, They're all generated for us. We have the index bid, which is the list of mix. We have the edit page, which is the form to edit the mix, we have the details. All of them got generated in one sweep. I took you through them one by one so you could look at the code. Now that we have a better understanding of what each page is doing under code that is generated is doing. We could just do the wholesale operations. You can do that for your classes, but don't get too ahead and start doing it for everything else just yet, because there are more things that we need to consider in the design, but no, it is fine. Now we have the capacity to make or enter data in the mixed table. And then once we enter data into that mix table and we build up that list in the database. We need to be able to present those to the users when they're entering cars. One thing I'm going to do is add this menu item or an unfamiliar item to the layout pitch so that we can navigate to it. And then I'll just Control F5 and just do a quick test just to make sure the code is working for me. Jumping over to the link, we can click Create New. And then the first one is Toyota create. And we see created. So we didn't write any code, just know. All we did was just follow one simple step of scaffolding or all the pages. And now we have all of these edits. We have the details. As you see, he came back with the standard buttons and links and so on. So I always thought bubble uniformity. We wanted to make sure that our buttons look like this for all our apps so you can go ahead and style them. Exercise flexible bootstrap muscles no. And start seeing okay. I want everything to look the same way. No problem. For now though. We're just want to focus on the functionality. So we're getting, let me just put one more in. At this point, maybe an administrator would be the one to manage this mixed list. That's fine. Now when we look at the create for car, remember that we had to come in until the field that will stick in the name. But no, we need to have a field for model and we need to have a field which is a drop-down list with the list of mix. What we need to do is jump over to our cars creates page and I'm going to uncomment this section for car dot name. No disk can be carved up models, car dot model. That is our new input for that section. But I'm also going to introduce, I'm just copying the form group. Once again, uniformity. That's what was generated In every time we want controls. I'm just going to keep it in that kind of format. Even if I'm typing it manually, sometimes you might have to do that. It's good to just follow that coding convention because that's for that layer that you want. For the Kardon model or for the next one, I would say Car dot mq ID. Now for the mic ID, we want a drop-down list. We don't want a takes the box. So remember that's informs we have tag called select. This tag allows us to put in options. The first option I'm going to say is select mic. All right, so that is the first prompt. But obviously, I'm not going to sit down and write in all the other options, Nissan and Toyota. Because if I do that manually, that negates the fact that we want to have that dynamic list from the mixed table in the select, I'm going to say ASP dash four. So these are tag helpers where I can see I want this drop-down list to be for car make ID. Then the next thing would be to say, where am I getting the items from? My items needs to come from some lists. So I'm going to see me mix. I'm just putting that out there. That's not the name of the list just yet, that doesn't exist yet. Hence, the red line. In the code behind I need to send or prepare at least called mix, which will comprise the list of me x from the database. So going over, I'm going to want creates our property rights on the dot one. Or actually I prefer to have my properties above my methods. I'm just doing this quick refactor. That's because I prefer to have it that way. If you have no problem, then no problem don't necessarily have to follow, but I like to see them all in one place. So yes, we know we have the car property. But then I went to say public select list. So that's a new data type we're looking at. And I'm calling this one mix. We do that Gita and sit. Then after I have the slit list on get, remember on gets prepares. Rather it is there so we can prepare all the data needed for the page. So prior to this, there was no data needed for the page. We just had to return to empty form. No, I need to actually get this stuff from the database, from the mixed table, fill it, or put it into this mixed property. And I think based on the name here, oh, I need to say modeled up mix. In order to have created mix, I can say modeled up makes apologies. That's a model.fit mix. And here's our appropriately called mics. I need to fill mix with the data coming from the mixed table. Otherwise, we wouldn't be any closer to accomplishing anything that we are. No. So I can see mix is equal to, I don't want to initialize a new select to select list allows me to pass in a collection of items. And then just like with the select tag or the drop-down list, I have something that is displayed and something that is being trapped or stored. In other words, when we're displaying the mic, the user should be seeing Toyota, Nissan, Lamborghini, Ferrari. However, while we need to track and store is the actual ID, that is why we said it is the ASP for the meek IID, meaning whatever I select from the drop-down list, look at its value and store that value in the make ID. However, I will be displaying the name that is associated with the mean. For the list, I'm going to see context. Context. Please give me all the mics and to list this is me saying give me all of the mix in the database. Then I will just say Como. The sorry, I'm just going to make sure. Okay, yeah, sometimes I get them mixed up. So we have the data value field and we have the data text field. So the value that we're checking is the mean, is the ID rather from the mixed table. And if you forgot, just go over to the mixed table to see what the field names are. The value that we're trucking is ID. We want to bring back the name. You also notice that I have this additional properties, so that's actually optional, but it serves the same purpose as when we put the mic property in the cars, meaning one car is going to have one meek. You can't have a car that you're going to call a different mix to either have a Nissan or I'll tell you what are some things. So it's one that's why in the car table, we have one ID to the car and one navigation property. However, Toyota makes many cars. So if we're looking at a record Toyota, there could be many cars that have the Toyota ID in them, so that's why we have a list of car so far, any mic record that we look at, we can actually see all of the cars that are associated with it's all related to it. While we're here, I can just mute this virtual. Alright, back to our code where trucking the ID, but we want to display the name to the user. This is just me seeing on get to linear load in the page. Please go ahead and run that query, fill that list, and then send back the page. Once we do all of that, I'm just going to save and Control F5 to preview. And here we are. I know it looks a bit uneven, but we can fix that. What we're seeing, the mic ID. So that's our label. We didn't type that. All we did was give it the label and say let me just jump over. All we did was say a label for cardamom unique ID. Well, we're seeing the label. If we look in this drop-down list, we're seeing the option select mic. We're also seeing other things that we didn't add as options. So you see that it is going to the database and getting Toyota and Nissan. Once again, the cool thing about this is once this list is updated, so if I say Ferrari and create, once I refresh the page, it will refresh that list and it appears. All right, that's the power of this dropdown list. When we want to restrict what the user can enter, we just give them a drop-down list and we maintain that table. Otherwise, they have very little control over what they can put in for that value. I mean, styling wise, what we're missing is or class form control on the select class equals form control. I'll just save that and refresh and allow it to compile. And that looks a little bit better. And then we can also look at how we can change all the labels. But let's try and create a car. Firstly, if I say select mic, I don't put in our model, I don't put the inner ear. So remember, one model is required here. If I tried to create, it will just tell me, Hey, you can't go any further until something is done. It's telling me the wrong wrong validation message here. And that's because I didn't update. This validation was far. That's one of the dangers of copying and pasting. Just make sure you cover all the bases. But hey, that's why we're here to test. If I put in Toyota, I put in the model Sea Harrier. The year is 2001. If everything looks valid and I create, then we see our list coming back with three. We add two before and oversee three. No, on the list, nothing is being displayed. Y is nothing being displayed on that list. Now let's jump over to the list and see. So we had commented out the name and the year. What I'll do is just uncomment all of this on comment, everything. The name is going to give an error because there's no longer name is no model. And look at this null when I want to see what kind of card the year. So it's a 2001 Toyota Harrier. What do I have, right? No. I only have the year which is 2001, mic on Meek ID, which is the field in the database. But obviously I can't be showing the users make IT. So I'm just going to display what the users would see if I said Meek ID, because the ID values are really for internal use, they're not really for a user visibility. When I refresh and I see this, no, the first two don't have mic IDs and that's fine. We understand why because they existed before we broke it out into the mic. However, I'm only seeing one. What is one? What is one higher? That means nothing to the user. So we already established that primary keys are useful for navigating. So in all which record we're looking at and which record we're targeting. In this situation, this is displayed, this means nothing to the user. That is why we have the navigation property that I was describing. When we created car, we made sure to put in that navigation property because no, I can see give me the mic that is associated with this car and I can get the details of that mic in the form of its name. So I can know just meet that quick change in my view. And I'm probably going to run it to another error, but let me meet that change, refresh and that is blank. Alright, let us see why that is black. It is blank because in preparing the data, I am saying give me all the cars. I need to tell the query that when you get me the cars, I also want to include the details off the mic. Getting the cars, yes. And he got the Meek ID, but it didn't get the details of the mean. I'm just showing you how everything is interconnected. So that's why I keep on showing you what doesn't work on how we fix it. So to get the details of the mic, I have to see cars dot include. Then I'm going to give it a lambda expression where they went through what lambda expressions looked like. I'm seeing include meek. So anytime you have a foreign key on a table and you have that navigation property and you want to run a query where you get to all the details from the foreign key table as well as the main table. That's all you have to do. Database Get me the cars, include the details for the related meek and then give me everything as at least after making that change. If I refresh again, then we see toyota. You see how everything just came together at this one. Once again, let me just review. I included the details of the mic in the query. In cars went over. It was easy for me to see, give me the car, Get me the meek, and get me the name. Now in case I didn't explain before what these areas subscripts are up here versus them not being done here, we just want the display name. So you could actually just remove this and put in your own display name if you wish, that would be fine. Name here, the name doesn't really mean anything. Okay. Yes, we had named initially but we had name I will route or Suzuki's in sport. No name is only going to be storing Toyota because model is there to see a higher. So this should really say something more like me. If you want to change what is being displayed, you can easily remove that code and put in your own. We looked at tables already. We know what we can put in our own text for the table header. With that simple change, when we regenerate the table or the page, we see it no printing meek. Alright, so you see how everything is coming together. So the thing is, we basically have to repeat that feed for anywhere that it is pulling data and expected to display something. So yes, we have it in the list, but let's go through this is called regression testing. Now, anytime you make a change to your system, you always wanted to make sure that whatever obtained and worked steelworks. We see that we've got the list working. We see that we've got to create working. If I look at edit and details, I'm going to see that, okay, Update still needs some work on it. And details needs some work on it. So let's change those old. So let's start with the updates because we already know that the update looks just like the Create. I just need to take the same fields that I have in the created for the select list and the model and put it over in the update, just over it that commented code and paste. But it's not just that. We still have to load this drop-down list because seeds completing it doesn't know what mix is. Just like what we did with the create where we had that property called mic. Someone's off to give you that property called mix again. Then I'm going to have to fill that makes property with data. So just like what we did that's on the on get here for the update. I'm going to have to tell it on get yes, here it gets in the car record to be abated. But then I'm just going to go ahead and put in that mix. So if you get the car record and it's not returning NADH phone dynamic, the next database called to get the mix, then we can return the page after making those changes to the update page. If I refresh, then I'm going to see that we have this happening. Notice that it's defaulting to select mic. If I go back to List and I choose one that has a mic, you will automatically bind and show me the milk that was selected previously. It is binding. It's, it's a bit intelligent. But because the others didn't have me, it gets not showing me anything, excuse me, the default once a value meet once a week idea was present you to the automatically bind on the edit for the details. Well, before we get to the details, let's make sure that this still works. I went to see this is a 2 thousand tool just as simple change, save, and we see that it is being reflected, so the editor is still working. That's good. We need to update the details know to let it know what is expected of it so I can uncomment that sick SHA-1 was firstly, I duplicated it, then I can uncomment it. This is no name, no longer name alone but dot name and this is no model. No details will show the ear, the mic name off the mic and the model. For our query. We need to let it know when you get cars first. Third default. Once again, please include the details of the mic. So include lambda expression and the mic on get, we get the car with the details. And then we can see everything. If I view the details of the Toyota higher nom, see everything coming back. Once again, we see that name right there instead. The thing is no, I went to I went to kind of hold back on changing the property here because we did it for the index where I change it manually. But then we might want to do for the details, but then if we change it money, will they ever were and then the client or whoever we're building the software for a comes and says, I don't like that label, change that label, then that's as many places as we are going to have to meet the change. Quicker way to meet that kind of modification will be to use annotations. Here I can see the MEC class that your display. Display. Then after include missing libraries control data and enter. Then name is the parameter. So your display name is just by changing that here are sitting that here above that property. Anywhere that display name for it is it's already updated. Anywhere that display name for beta of code is being used like it was being used in the index. Before I change it to seed display name for that is automatically going to look for any data annotation above that property that sees display and then use that text. That would actually spear me the heartache of needing to change that money while they everywhere, I can revert to display name for the index. I can keep it in the details because there it is display name for. Then everywhere that it is being referenced, it will automatically use that taste. Alright. I'm just showing you a nice cleaner ways instead of retyping dry. Don't repeat yourself. That's one of the fundamental principles of solid development. So as little as possible should you be retyping code always look for a solution that has a more global reach, as opposed to one that requires you to keep on doing the same thing over and over. Now, let us try and create something else model. Let's call it a Tesla, year 2221 create. All right, so you see that this is not valid for me ID. So this is one of those default errors because we didn't put any error message over it, but it is just rebuffering us and seeing that it is not valid for Meek ID, so validation is almost automatic at that point. In the same way, if I have an invalid date, year other than you see the field ear must be between that message. That message is coming up because we put on the range for the detail. These are ways you can enhance the UI and enforce certain rules for your users to preserve your data integrity. 18. Form Enhancements - Part 2: All right guys. What we want to do is continue building on how we enhance forums and the two things that we have to do to make sure that we provide the best experience for our users. Know when it comes to the validation steps, views would notice that our is valid does not get hit when we tried to submit the invalid data. And that's really because we have the validation scripts here, making sure that only valid data gets beyond the client said and that's good. But then in the event that there are certain circumstances where it may think it's valid on this side, but then we need validation in the server side. So this is client-side validation. You have heard me talking about the whole of the clients. I think client-side validation occurs on the front end, right? So between JavaScript and HTML, we're letting the users know what is valid, what is not. If I use a turns off JavaScript, they can easily bypass that mechanism. Also, there might be times when certain validation rules have to get evaluated on the server side. So if you have a complex logic, like maybe you have another validation to make sure that the model matches the car mic or something like that. Whatever it is, it's complex. It can't really be portrait in our ESR nor is it required, or is it between these values. It's not really a Boolean or something that's quickly. And then we would have to build some more complex validation rules in the server side or in the code to ensure that it is valid. What I want to portray right now is what happens when maybe it's client side validation is not running. To do a quick experiment with that, I'm just going to comment out the validation scripts partial. So a quick way to comment, put the cursor on the line control. Casey will comment and the control key you will uncomment. Holding down Control. You press key, then you press C, and then it will come in. And then you do the same with key and you, and it will uncomment. I'm disabling this script that is running on the client side. And I'm going to put the break-point here so that we can see what happens when something is invited on the forum. I'm just going to click Create and look what happens. It jumps right over to the post. So there's no validation message. Remember last time we would always just print all the validation message off the button. No, no client side validation is taking place. So our fail-safe is this model state, model state DOT is valid, is valid, retina is false. If we look in the model states, just so we can understand exactly what's happening here. Lucy, validation status in valid, how many there are, then you have the keys and results. So let's go to results. Results would show us the keys and the validation sets of each key. So the key here would be each value that is in the model being validated or modulus car. And the validation would say that the year is required, model is required, make ID though all of those are required. No. None of them was provided. All of them are invalid. And then if you want to drill down into it, you see the key, you see the value, and then it will kind of give you some other details. Attempted value was that there are a lot of things you can't get out of this model states. So here's that exact error. It's saying that the value which is an empty string is invited. That's the erudite you're going to get there, press F5 unlimited, continue. This is what prevents old. So we're getting that validation summary and we're getting each error underneath each field. So if I put in something that is outside of the reentry, did say the range is 1999 to 2020. So if I put 1990 and try again, then it's still invalid. I press F5 again. No, it's going to show us a different oh, sorry. I should have said 1900. That would've been invited. Let me try that again. So create heat, the breakpoint, continue, and there we go. So the field ear must be between 19902021. So we're seeing all the validation where we are familiar with this Randolph. That is what? Server side validation reset the table if somebody disables their JavaScript in their browser, or for whatever reason the area with a bypass the JavaScript because everything with HTML and JavaScript and CSS is available to your users. So this is about secure coding node because all I have to do is inspect element. I can see everything above the code. I could modify this certain things. I could choose to disable this script on this page, stuff like that. That's hole, the hole important or server side validation step is to ensure that we don't, we don't return any garbage to our system. Now another big issue that are a big issue that we definitely have to address is the fact that I was just going to start over. We go to create new. We have our list of mics aren't fun. I went to say Toyota model, car model, whatever. I click Create, winter, remove this brute point because we know that it's going to be invalid because there was no model, no value for the year provided. But what happened to the meek? Look at that, that list has disappeared. What happens is that when we're dealing with select list and certain types of lists in the post, you always have to make sure that if you are going to end up returning the page, you need to return the page with all of that additional data. Because right now the only data that is good to persist is anything that has the bind property above it. Even if I see Ben property above the select list here, the reality is that there are no fields on my form to store the whole list. I have a field to store the ID that was selected from the list, but not the entire list. This list has to be refreshed every time this page loads. Just to say we don't get to go and get the list from the database and per period. So it could be loaded when I am invalid or the pH, the submission is an in an invalid state and the pH has to be returned. The pH is going to have to be returned without mix in it. So I went to run an example of what I mean here. I'm just going to put some code here that is just going to say var mix. After submit is equal to mix. We're going to look at what is in mix before Submit. And then we're going to look at what happens to mix after a submission. So with the latest versions of Visual Studio earlier in debug mode, you can actually just click, Apply code changes. Then go back to your code. I'll just refresh the page. All right, Let's just go through this again. I'm going to try and create and I'm going to send over something that's invalid. I'm going to put back my breakpoints so it pauses so we can look at what value comes here. I'm also going to put a break point here before it returns a peach. So when I see, Okay, let me just refresh. Let me do this again, sorry. So create noon. Then when I do create new, it hits this breakpoint for the page. So if I look in mix, I'm seeing that mix is it has data. It does still have that suggests that it has data. It has the items that will be going into the drop-down list. Alright, that looks good. I'm just going to remove that breakpoint. Send over something that is not valid. When the break point was that the if statement, it didn't hit it. So I'm just moving it up to the line 34 for me or the first briefs off the method. I'm going to step into this and then let's look up mix, mix is null just to drive my point tool and that once the data is submitted, your select this and basically anything that is at least that is not being boned or that cannot be boned is going to be empty. Once you submit. What we need to do is refresh that list. I'm just going to stop. And we're going to do that bit of code to make sure that the page is always provided with its select list. Or in a case where you have multiple drop-down, this is the same concept. This makes sure that all of them are populated with the data when the pH loads at all. So I could actually just take this bit of code and place it here. If the model state is not valid, then reload the list of mix and then return to page. Otherwise, just go ahead so it won't waste the database call. If the model state is valid, then it won't do any of that. It will just jumped onto this and proceed. Know what I don't like to do is repeat code like this. Why did it seems simple and it simply enough is small class file and it's really just one line. But then what do something changes? Remember, I said that the more you repeat midst of code around the application is, the harder your maintenance will be when something changes. What I tend to do is have a private methods. So I'll just say private task. We'll just say private task. And I'll make it an async task. Here. Call it populate, drop down lists. It's one would just call it populate drop-down lists. And then inside of that, I make that method call. So this would know b. And I can meet this asynchronous associates at least a sink which which needs me to include that library. And then I can meet this wheat. All right, so it's an async method. I wanted to make use of the asynchronous methods. What I do know is just call this method everywhere that I need to do that population. If I have multiple drop-down lists, I need to populate. I just made I just put them in here once I call that. And then he can do that because there are other situations where you might need data that is not being trapped on the page. You may need it to be present on the pH if the model state is invited. So you can, why I'm calling populate drop-down this, you could also call it like Lord, initial data. So any queries, any operations that you need to carry out before the page is visible, you put all of that code here so that we don't have to repeat it in your handlers. If you have more than 100, only 100 doesn't really matter. You don't have to repeat it. No, I have to await it when I'm making the call because it's asynchronous. But then up top, this one is giving me an arrow, and that's giving me an error because this method is not asynchronous. So let's convert this one to async. Async task. And this task is expected to return something of type i action result. And once I have done all of that, all the red lines glowy and everybody's happy. I'm just showing you a little pitfalls or things to look out for when you are writing your applications. 19. Improve Data Collection Forms and Validations - Part 1: Alright, so we're building this application and we showed our stakeholders because at the end of the day, most of what you're going to be building, you're going to have to demo to somebody. While you test it, while you develop it, you test it. Um, you're either guided by their expectations in the form of software requirements, or you're being guided by what you think they need, which can be dangerous. Because in this situation without any formal requirements given, they have given us some feedback and told us that certain things will definitely need to be changed. No, number one, they're saying that they need more information about the cars to be stored. Know the year, the mic, the model. That's not enough information. They need us to say what color the car is and to provide a license split number, which I think are sealant points. Another issue that they've pointed out is that spelling errors can occur because we left model as a free text field. While music is a drop-down list, model is not. And we discussed the danger of that earlier. So for the very same result we made, make a drop-down list. We're going to have to make modeller drop-down list. That comes with its own challenges also because model, we can't put a randomly model. So for instance, one Nissan, nissan, Sony with an eye. Those are spelling errors. However, nothing is stopping somebody from typing in Ferrari Sunni. And if you know anything about Ferrari's, you know that they do not have a model called Sunni. So they also said that when you select a mic, they wanted to make sure that the model that they are able to select afterwards actually applies to that Meek. Those are some requirements that have come our way. We've, we've actually done stuff surrounding some of these changes already. And let's see exactly how this will work. So the first change that I'm going to make is to the car entity. Remember that we had introduced mic, we need to introduce more fields and we're not, we're already familiar with what we need to do to introduce new fields. The first field, I'm just using Control D to duplicate so I don't have to type out everything from scratch. The first field would be string. This would be color. Color is also another sensitive topic. Because somebody can write blue, somebody can write B0, somebody counteract black and forget the c. So that is another sensitive topic. Do we want to leave the color of the vehicle as free text? Or do we want to lock it down and have it in the list? These are decisions that we have to make to ensure that our system will be due right by the users. Personally. I prefer to have colors in a list because then the chances of users entering incorrect colors are colors that don't even exist is greatly diminished. Just the same way that we have the caller ID. This is going to be a foreign key. So let me, let me backtrack a bit and I'm going to introduce the new fields in the order. Alright, so underneath me, I went to save public int and I'm making no level. So remember why we had to make this available. We're introducing a foreign key after the fact, after there are records there already. So we wanted to make sure that we have very few conflicts with the foreign key values. We're going to have another property, which is going to be a virtual property and went to call it color. It's going to be called color itself, type color. It's going to be called color, no color. Look at this. I can just do Control dots. We don't have a class called color. So I can see generate a type called color. And it will ask them, do you want it to need in a new file? I went to see it, yes, because I wanted to denote new for us. There it has appeared as color and that error is gone. So that's a nice quick way when you're creating new types and you haven't created them vtable, you're flushing or what you need to do. Visual Studio has suggestions to help you be more productive and not focus on the small things. That is color. What do I need? We need the list for model. Model is going to suffer the same fate that name suffered. Some just going to remove the model field. This is going to be a model ID. You'll notice that I always go back and correct. Leave off something that's not capitalized or how a spelling error I'm always gardening because when you do it right the first time it goes up firewall. So once again, with model, I am not linked to using any library. I actually wanted to generate my own trust. And then model, as you see, is actually like a keyword because it's model. You would have heard me talking about models when we were talking about Entity Framework on so on. So it's kind of risky if I just call the class model because I don't know what other name or what other data type I might be conflicting with. I'm going to call it a car model, just to be on the safe side. The datatype I'm creating is called car model. But then I'm going to call the field inside of my class car, just model. All right? Once again, sometimes you name it differently. Sometimes you name it the same way if you needed to see him, we know problems, so let's just name it the same way. This is car model, ID, car model, and the field car model. For our new entities, what do we need? All of them need just like what may cut. They all need an ID. They'll need a name, and they will all have that list of cards. So actually, these fields can be replicated easily across all of them. So for color, we have ID photo color. The display here would be color and not meek. So you see, I'm copying and pasting didn't nothing wrong with copying NPC1L1 to understand the concept or what you're trying to accomplish, you can always copy and paste and speed up your productivity. Alright, so we have those three fields in color. And then I went to do the same thing in our car model class using control dot to include any missing references. Then this one would be here in the discipline name. I can see a model because we know we're looking at the car, so I don't need to say car model to the user. This is only because I'm trying to avoid conflicts and this is more experienced stalking because I have encountered that before. So don't feel any way if you're wondering, okay, how do I know when there might be a conflict or not? Sometimes it's trial and error. Sometimes you do it when you try to run, you run into the problem so you change it. No problem. We have car model color, we have car and we have Meek. No. Another thing that I'm going to point out at this point is the fact that they're all kind of using similar fields in every single one of these entity models so far has the field called ID. Let me just space them out as much as these three have all three fusing common car doesn't have any, anything else in common. But my point is that instead of repeating ID, ID, ID, ID, ID every time, one thing that you can do to once again reduce the repetition and increase extensibility and shareability across the code is introduced what we call a base model. So I'm going to create a new item that I'm going to call base a new class or other because I'm calling this domain in tutti. And then I'm going to meet this public abstract class. So it's abstract. Abstract classes basically mean that they're there, but you can't have an instance of them by themselves. You select go with car. We can instigate are initiates or other car here I can just call on car when it's an abstract class, you can't just call this entity based domain entity anywhere. However, it is good for inheritance purposes. So from here I went to say prop int id. Know that I have this field here. I can to every other one. Everybody who needs that ID field to just inherit from B is domain entities. When I do that with car model, what you realize is that this ID lights off. Now, the message it is going to tell me is that this property here is interfering with the inherited one. So it's seeing a conflict, it's not an error, error. You just warning you that if you intended to inherit the value of this one is always going to take precedence of the inherited one. But the point of me inheriting that I don't want to see it there. Anytime you have fields, so they're light later on in your career, you might start talking about auditing, where you want to store who created a 10-watt date. It was created. When you have those kinds of fields, you just put all of that in the base domain entity and then you make sure that every body who is a database class inherits from the base domain entity that we every class will have those fields regardless. This node will reduce their repetition. So the next time I have another class, I don't have to spend time putting the appropriate tinnitus that inherit. If there are five properties that IVR class should have or every table should have in common. I just put them all in the bass. Everybody inherits it. All right, so I'm just going to do that for all of my domain entities. So cars set, CAR model is set, color is set and make you sit. Everybody's inheriting from the base. So if I wanted to, like I said, just extended prop. So let's say I wanted to know when was it created. So prop, time. Date created? No, I can say okay, I know when this model was created, this MOOC was created when this car was put into the system, etc. These are all the important bits when you're dealing with systems. With these changes in place. Let's jump over to our Package Manager console. And I'm just going to add a new migration. So I'm going to say added more car data tables. That's my message. I'd migration and whatever message describes this whole activity as best as possible. And then let it go ahead and generate that migration build field. Yes, of course, abilities to interfere because all of my views that have model are not going to cry out. Similar story to what we went through with name. But once again, it's better to get this done while we're in the development stage, as opposed to when you're in production. We just quickly go through uncommented all of those fields that's had a dependency on model. And I'm going to try that again. And this time we get our migration. So let us look through the migration quickly. We're seeing that we're dropping the column for a model where adding the column for date created and it's added, being added to mix. We're adding the car model ID to cars, the caller ID and the date created, all of those are being added to cars. And they were creating the additional tables. And then sitting up those indexes and the foreign keys that weren't there previously. Of course, the dome is just undoing all of that. Should we do a remove migration? After all of that, we went to do an update database. And if all goes well, we get the done, we're done. Now let's update our fields. So back to the Create. Create no longer has car model. Now we have model ID, model ID, and we have validation for model ID or sorry, car model, That's the name of the field. It's CAR model ID. And then we're actually going to have a select list, just that this for the models. So we're going to do mic, then select model. Then our ASP items is not coming from mix is going to be coming from a field called models that we're going to be sitting up in a few. We also need to extend this list to have a facility for our colors. Just the same way we have to put in the models. We have to put in our caller ID, caller ID, select color. Then this will be coming from a list of colors. All right, great. So that's it for or create. And what I'm going to do just to make this very easy once again, copying and pasting nothing wrong with it. I'll just jump over to the update and change that thought because it will be the same dynamic really. That is it for the update for our index, we can uncomment this and then put car model ID. So it will be CAR model name. In the index. This we want to show the year, the mic, the car model. And let's say we wanted to put in the picture, sorry the color also, it would be color dot name. You'll see the importance of the navigation fields. And then we uncomment. So this is car model, dot name, color, dot name. Alright, so this is just extending that. This is a normal part of any software development process. You're going to do something. You're going to get feedback, and then you're going to have to undo some things and redo some things, do new things. It's just a normal part of software development. So we've updated our index or update or create. So it's just the details now we'll just update that. We can do the others for the details. Also. Know in doing this, it actually occurred to me that there was one thing the customer asks for that we did not put in and that is the license plate number. We put in everything but the license plate number, not at this point. Once again, you have two options. He can either undo all the changes you made to the database and then put in the missing field. And then. Redo the migration. I'm not going to go through all of that. What I'm going to do instead is C Public license plate number. I'm going to use a stream because license plate, while it's called number, is not really a number. Sometimes it's alphanumeric. I can my country it's alphanumeric. And I have a general rule of thumb that I don't use int and double or any numeric datatypes unless I went to be using this number to some form of math. I simply add while it's called number and while it may be strictly numerals in your country, It's not going to be used for any significant kind of collisions. Full number I wouldn't store full number as a number in the database. I'll store it as a strength because there's somebody puts in hyphens or the brackets and so on, then it's no longer just a number. If license plate number comes with letters, just during a test string has no consequence. Whether it's all the numbers are alphanumeric. I'm introducing that new field and all I'm going to do is just add another migration saying I did license plate number. I keep on typing name. I'm sorry. But I'm getting a build field. That's because we don't have these yet. So what I'll do is comment these out onto migration is done. Let's quickly, Let's try that. Migration again. People button name. I don't want name. I went to remove the migration and I went to correct it and see the license plate number. And then we get the migration where it's saying it's just adding the column law problem. We could put validations on it. So sometimes you do something and then you're like, oh snap, I forgot that step. So let us go back and just do it. License plate numbers are going to be required. And I'm going to sit a string length of ten. That's generous in my book because I don't think anybody really has a lesson plan number of tin in my country, they are six characters long enough you're going to reserve or lower, they're up to six, but that says put it to ten. So nobody should be able to write an essay in that field. Let's do that again. Now I have to remove migration and then add migration. It's a good thing that Microsoft doesn't charge us every time we were in this statement, we can do it as many times as we need to make sure we get it right going into the database. So you see here it's invar, char tin Muslims and not nullable. That's fine. Then I can see update database. That is done. Alright, so now we have our license plate number introduced. I can go back to my forearms and I can put in that input for the license split. All right. So I can uncomment this. Gordon, come in, make sure if explained in Titian, put in lessons splits number in the form. Then do the same thing for the update. So uncomment all of this and introduce the lesson split number field. Once again, I'm following the same format. So even though if I need a new field, I'm just going to copy this, paste it, and then change what I need to change. Note that all of that is introduced. What we need to do is make sure that we're loading the other drop-down lists. So right now we have mics. I need one for the colors and one for the models. Just the same way that we had to load up mix. We have to load up colors and models. So we can just easily do that one please, without duplicating the effort in both the GET and the post, I can do it one please and see a load initial data. Here. Sit the models to be context dot Models.swift list. They're all the same kind of format and that's really car models. Sorry. I didn't name. That's fine. Then we have context dot colors and we have ID name. They'll notice that I'm getting these errors. And if you can tell me why I'm getting these arrows, then kudos Steve been paying attention. If you can't tell me, that's fine. The reason we're getting these errors, let me just change that quickly. The reason we're getting these areas is that the context does not know anything about car models or colors. So I'm here trying to access tables that the context doesn't know why it doesn't look contexts now, while we put them in the database and we created a entities, we still need to put the DB sit. I need to see. Please struck this entity called car model against a table called car models. And color against color. Now, this is a good point to point all these nuances because it's easy to miss these little things. And I made these mistakes deliberately just a point or toll being consistent is very important. Remember that this represents the name of the table by saying DB set CAR model and car models. If I had put this in before doing the migration than the migration would have said that the table name is car models and the table name here is colors. But because I did the migration already, look at what happens. The name of the table is car model, and the name of the table is color. So be very careful about that. Whatever the table name is here, you want to make sure that you kind of mirror that on this side with the name that you give it and then that kind of looks mismatch to me. The cars, me. I don't really like when it's like that. Once again, they don't charge us to run migrations, home and immigrations urine. That's really up to you and how many migration files you really want. But once again, as you practice more, you make fewer mistakes like this and you'll see them do it right the first time. And then you realize that when you need it to run five migrations to get one thing done, you just wrote into more straight. Now that I've put this in car models and colors, I can go to the pockets Manager console and run a migration. And I'm seeing carted table names, so that's my migration. When I get that migration file, I'm seeing that too, just dropping the foreign keys, dropping the primary keys, renaming the table, then it's adding them back. It does a whole step-by-step process of how it handles even renaming table. It may seem simple, but I never fully appreciated what databases go through in the backend until I actually saw what kind of migration code was being generated for what I perceived to be very simple operations, right? So it's always good to let them migrations handle these kinds of things. You just add the migration when you need to. So we'll just update database. And once that is done, and once again, if you're encountering arrows, you just come into the code. Probably in the form, by the update form would probably have some code that will cause problems. You just comment it out, do what you have to do, and then we get back to it. So back in our Create now you see that everybody's happy. We can load initial data. We didn't do this load initial data in our update, and I would suggest that. So I'm just going to uncomment this code that was causing problems. We need models and we need the colors over here and went to have that private method. All I did was copy and paste it. Then I went to tell it, go ahead and generate property for models. So you see that? Then go ahead and generate a property, four colors. Now if I look at the top there they are. Using Visual Studio as a productivity tool. It's helping you to focus less on the little things and just get things done. Just that I know have my select lists. What do I need to do? I need to call my lord initial data method. One. When I'm about to return the page, I call load initial data. That's asynchronous after our weighted. Then if the model state is not valid, then I have to call it initial data again. That's it. All right. With that, we have accomplished a lot. And even then you could probably abstract this functionality built into a helper method that does that for you. I'm not going to get that technical and complicated just yet. I'm just giving you the ideas, but you still see that we have to repeat this method here. And in the create and maybe other pages where you may need to list them. So if you want to reduce repetition and that's when he started seeing, okay, how can I create one file with the method that multiple places need to use? So I can just call it and have all the code in one place with all of that said and done. However, we have accomplished a lot to have extended the tables. The car table we have creates a new tables and we have facilitated for new drop-down list snow. When we come back, we're going to do the scaffolding for the new tables because we did that with mics so that we could maintain the list of mix. We need to do that for the colors and for the models. And then we will also look at how we can control which model comes up when a mic is selected. 20. Improve Data Collection Forms and Validations - Part 2: Hi guys, welcome back. Last time we left off with just putting new tables and we put in the drop-down lists, but we need to actually put in the crowd beaches around these lists. I'm going to do one with you and then I'm going to challenge you to pause the video and do the rest on your own. So let us do the scaffolding for our car model pages. And then we can add a new folder. So I'm just going to say car models. Then instead of that, I went to add a new Razor page, Razor pages using Entity Framework crude. And then we're modeling of car model. Go ahead and hit Add and barring any errors, which once again would be because you probably just need to go and roll back to previous versions that would've worked. You can see your car models has been scaffolded. I encourage you to hit pause or just do the same thing on your own for colors. If all went well, then you should have a folder in your page is called colors. And all the crud pages. What I'm going to do is quickly go to the layout and add the new enough items. So I'm going to remove privacy because I'm really not using that privacy linked. So we have cars, have mixed models, we have colors. Of course he just changed the path to the root of unfolded name slash index. At other challenge that I would give you guys is if you are interested in extending the same way we did the delete off the cars. So remember in the index page we did the whole suite alert and delete form on the jQuery to fill the Delete form and the custom handler for the delete. I would encourage you to just try and do that on the others. That's where practice comes in on car models. When I'm looking at the list of car models, what if I wanted to delete them? Well, we can put in jQuery and everything and put it into custom handler. And you wouldn't need the Delete Page. I'm encouraging you to try it out on your own. We did it one time, review how we did it and apply the knowledge because that's really how you improve as a developer. Let us test owed or application. Let's go over to models and I'm clicking models and nothing is happening. And that is because of the wrong folder name in the layout. So my bad Shun, refresh. Try again. If I go to models There we are. Now we're in the car models for this, I went to add a new model and this would be a Sony for Nissan. Now, notice did create it. I don't want the user to tell me when it was created. This is something that should be automatic, that I want that to happen in the background. I don't want this shouldn't be on the screen for the user to see and tool that needs to be happening in the background. So bear that in mind later on when we start looking at the models. Because when we're using the data models, this is one of the limitations we needed for the database or don't want it for the user interface. There are times when we'd have to create a separation between what we showed the user and what do we actually store. This is one of those situations. We don't want to show the user this field at all, but we do need to store it anywhere. I'm just going to proceed by seeing model is Sony. Go ahead and create an ISI notes intermediate created is required. Why is this required? Because we did not put their required over it. However, the datatype it uses is the time, which just like the int, gives an automatic requirement. I'm just showing you hold the dynamics of all of these things when we put things in. If necessary, to consider the full picture just yet, or when we encounter these kinds of issues, how we can work our own, they're more to understanding towards working our own them. That is why I did required date created sorry, is being stubborn and telling us that heat is required, so that's fine for now. Just to get beyond this home, please just put in a date created. And there we go. So we can add a few things. Spider, that is Ferrari, just made that today Create. And we have Toyota. Harrier was the first one in our system. What other? Sorry, I don't remember what the mix that we have, so let me just look at the mix. We have Nisan. I deleted the extra ones, so we have at least one to 2171 Ferrari. That's good. In our models. We have those. No, I need some colors and I'm just going to keep this simple. I'm just going to say black and blue. And blue. When I go to create a car, cars and I say Create New. I get the drop-down list for me. I get the car model. But I'm seeing all of them. I could easily say Toyota spider. Then we see the caller ID, black and blue, the year, say 2020. And the license plate number, like I said, in my country, can be alphanumeric, so it could be 1234 AB. That's the general format we create. We at least see that it's created, but we're not seeing model, we're not seeing color. Where are we seeing modern color? Photo one we just created. We're not seeing it for the same reason. We didn't see the mic initially because in our query when we're getting by the index, so let me just jump over to the index for the cars in that query. We have to include. So I have to make sure that I say include. What I'm doing is just breaking lines so that I can just Control D on this and meet my life much easier. Working smarter, not harder. When it gets the cars include the mic, the car model, the color, and then latest version of Visual Studio Code, apply code changes. Go ahead and hit refresh, and we're seeing at least with color comeback. So let's go and debug and see why we're not seeing the model. So I did all of the Includes. You can go ahead and restart if you're already running in debug mode, I put a breakpoint here so that when the data loads it will pause and allow me to go in and interrogates five cars. When the car that I just added has to make ID, but it does not have a car model ID. That means something went wrong with the form between the form being submitted and it getting here, something went wrong. That's fine. So let's go over to Create and see what might be missing. So that is the problem. Wow. Copy NPS. While it is good. Just be very careful. I was still binding it to the wrong field, so it should be mic. I save that, refresh or Apply code changes. Let's go and try this again. Go ahead and load the Create form. We get to the spider block 1990. And I'll just reuse that lesson split number. Remove this breakpoints points. So it just goes ahead and loads and there we go. It's coming button or the binding is happening as we expect. That's good. That's wonderful. Battles fought. If we go to Edit nowhere seeing all of what we had Putin. If I change this from black to blue and from Toyota to hire because they realize, oh, I made a grave mistake and I click Save. Then we see, we're back to square one. We're about to square one because I updated the create and I use the same code here in the update. The update still has that error. Regression testing always important anytime you introduce changes to your system, go back through and make sure that what used to work steelworks. So let me try that again. Save and there we go. No, the edit is working, creates these working, all of those features work. Does the needs to work? Let's check. Alright, so everything works the way we lift. It's the next big ticket item was that when we create, we want to make sure that only the respective model relative to the mic exists. That means when I create a model, I need to let it know which make it belongs to. And then tool when I select a mic when creating the car, I need to make sure I'm loading only the models those relate to all. Alright, so that's very important, that's, was very important. They stressed apart in the meeting. So let us see how we can do that. So the first thing we need to do is introduce a mic ID. So we need to create a relationship between the model and the mic and think about it conceptually. Because, I mean, if you have a car and you know that you have certain brands off cars that time, certain models. That's our relationship. So if you were to do a crossword pauses, Laura, one of those crossword matching activities where the brands on one's head, on the models on the other side and it should match the ones that relate to each other. It will be the same concept as a foreign key when you draw that line between Toyota and Harrier or Nissan and Sony, that is using that they are related. So that relation is seen as a foreign key, which is what we have been doing up until now with car. Let us. Jump out of testing mode and go back into extension mode, go into car model. I went to introduce a foreign key. I already have that kind of foreign key here in make, ID and car. So I'm just copying that, jumping over to car model. And then I went to introduce it. Now I have that field to let it know that it should be related to a mic. In the same way. Because of this relationship, I can go over to MIC and let it know that it has a list of car models and see how that works. So with that done, I'm sure you guessed it, we need a new migration. So add migration, model relationship, that's my message. Then we get the migration file, which is not doing anything fun. So we already know we can look at it. We just know that okay, it's doing the right thing. We can update the database and when that's done, we can move along in the crowd for our models, car models. We need to extend the create Peytchev, a drop-down list for the mix. And we need and also the Edit, sorry. So I have that kind of code already. Once again, work smarter, not harder. So I'm just going to take this form group. I'm going to jump over the car models and I'm actually going to remove the date created. So you can actually just remove the field. You don't want to feel it on the page, you remove it. Here. The binding would be CAR model dot make ID were taken from mix. That doesn't seem to exist, but that's fine. Went to copy this also. Go over to the edit tab. I don't want the date created. I need to retain the ID door. Remember, always retain the hidden. But I don't want that sexual and I just wanted to make ID part. Alright, then I'm going to have that load initial data so that initial query that we run when we had to fill the data for the page. So I'm just going to jump over to car models. I went to use the method, went to remove the excess. I don't need those two. I only need mics. So I went to create that property. All right. And then include any missing references. Then here I'll just do my lord, initial data call. And I'll do the same thing before returning the page. And this is all in the create a sink, some kind of speeding through this because this is stuff that we just did and I'm really just copying and pasting the code that we already went through in detail. So we're not doing anything special at this point. It's the same thing. We're just reusing code that we wrote and we know the concepts of if we do that for the query, we have to do that also for the edit, which is Into have it's going to put it here, bled and generate this new property. And then we make our call, our weight load, the initial data. We made that call up here also in the gates before we return the pH that we're done. We're done facilitating make ID for our models. So let me run, jump over to our models create. And you'll see here we're getting the list off mic. We have the capacity theoretical model, someone to say Sony. And you are related to Nissan. I don't want to create that one. All right. So actually I'm just going to delete all the previous ones. So it doesn't middle click them, open them in new tabs, delete. So I haven't, haven't extended this stuff, the lead functionality just yet. That's no problem though. It still works. So delete. All right. Oh, I thought they'll worked well, they don't this one is in the delete conflicted with something and husband terminated. And I think that is only because I'm deleting something that shouldn't be okay. Deleted. This deletion error is really because we created a car that has a relationship with this beer that's in mine. So let me point this out from the migration. Like I said, whenever we see arrows, I'm not skating skirting policies arrows because there are times when you will learn the concepts without seeing any Arizona when you get Arizona and a lot to do so, it's good to see the Arizona understand them. When we created the migrations, most, if not all of the foreign keys that were added, were added with the unduly is referring to actually restrict. If you're not so familiar with databases. What happens is that you have the referential action which allows you to either say, when I delete the parent record, meaning you delete a car already. I didn't need like car model. Then delete all of the cars that have that association. If I was to delete a color, Let's say I delete that black and add 50 cars in the database as black. If you wanted. When I delete black, it would delete all 50 cars as block, then you would see a cascade. Cascading action means delete everything related to this record. What our migrations give us those restrict, which is why we're getting that arrow because it's saying you're not to load tool, remove a record that has 200 records. So something is relying on this record. So I'll know is relying on the Harrier required that we have I cannot delete Harrier until I delete all the cars that are carriers. So Dr. Glenn delete all the actual car records that are hires, then comeback and density. Yes, I wanted to do the tire. That is basically what this is saying. It's an error, but it's not really, really, really an error. That's fine. I'll just go ahead and add new ones. I notice because I took off the date created, it's defaulting to a deed. So it's not telling me that it's required because it's not on this screen to think it's required, but when nothing is provided through it, it will get a default value just like this, just like within T, if nothing is provided, it will default to 0. This would be spider. And spider is really relative to Ferrari. And the other one that we had, Let's just add another barrier. And this one is Toyota or let me use another one. Let me use lexoffice or supra. There we go. So supra Toyota create, we have at least three records that are directly related to mix. One that is still kind of free status. So when I go to cars and go to create, the expectation is that I shouldn't be seeing everything in the drop-down list like this. If I click Toyota, I should only be seeing that Toyota related on if I click Ferrari at least switches and ownership over the Ferrari models, that's what the user expects. Obviously that's not happening now, let us implement logic to meet that happen. 21. Add Cascading Dropdown Lists with JQuery - Part 1: All right guys. So when we were last year, we were sitting up our form and setting up our drop-down lists for mixed models colors. No. The next big ticket item is that they want that when they select the mic from the list, it automatically will filter the list of models for display. Let us review what we have right now. We have our form that has all the mics listed in all the models listed. So don't want to tear a hole. I change the mic. We're still seeing all of the models. All right, so that means when I choose in the sun, it should only be seeing sunny based on the data that's in the database right now, when I choose ferocity, this list should reconfigure and only show spider. That's what we need to implement. And the tool that we're going to be using is JavaScript or jQuery. Jquery has this feature called ajax sets of those actually do what we call asynchronous calls, told the server side code from the client side. In other words, we will be inside of horse static HTML section, but we'll be hitting service said myths, loading the query, getting the data, and then bringing it buccal with the decline and said all in real time, let's get this party started by going over to our Create page for the cars. And what we're going to do is override the id value for the models. We're also going to add over at the id value for the mix. Now, a quick explanation. Remember that the ASP dash four is that tag helper that when the page gets rendered is going to give us the name attribute as well as the ID attribute. Now when you have that kind of double-barreled name like car dot Meek ID. The ID itself is going to come out as car underscore Meek ID. I don't want such a complicated ID, so I can always override it with my simple one. So I'm adding ID equals mix to the mix drop-down list. Id equals models to the models of struggle. Next up, I need to add some JavaScript. Remember that what we want accomplishes that when you change the mic ID value, we are going to be dynamically loading or changing the values that are available in the model drop-down list. I'm going to start off in my sexual enforce groups with a script tag. Remember that that's what this section is dedicated for it tell me wanted to write JavaScript. Always create that section. And then you put in your script tag, and then you can proceed. Let us start off with our event handlers. So I'm watching for a value change event in the mix drop-down list. We've seen that we can watch for a click event on a button. So pretty much you can watch for any kind of event on any kind of control, the type of event you choose to use, the ISR relative to whatever operation you're carrying out. I want that when I change the ID value here or the Meek ID value, that it will do something else. I'm seeing. Watch for my element with the ID Sumer bone wouldn't want an element by ID. We see a hashtag, then see the ID mix, see how much easier that is. Then the event we're watching for is a change event, is going to watch to see when the value is changed. And then we specify that we want to run this function whenever that happens, function to get the spinning red. As I said, a retirement open-air clause from the get-go. And so that's I don't forget. And then break a few lens and then we can start writing the code here. The first thing I wanted to do in this event is get the value. It has changed. What is the value nose? I'm going to say var make ID is equal to this. This object represents whatever control triggered the event, this dot value. Then I want to Sit the default values inside of the model. So the lie of hard-coded that what I'm going to do is actually just take it out of the select. So I'm not hard coding it because we're always going to be changing the values. What I do want that the HTML in there is that default bit of text. So I'm going to say, get me the element by the ID models. Remember, select ID models, give me that element and set the HTML in that element to be option. So this will be scared, just append the HTML, whatever the control is. It will just add the HTML, whatever you put in here with that inside of the tags. Anytime you wanted to manipulate what is inside of a tag, maybe I have an empty div. We want to put another element in there on the fly. That's exactly what we're doing. Now we have the empty list. Yes, it's getting the items from models and I could leave or remove that because on the first load I don't want it to have any items removed that whenever this is changed, then it should at least sit that default. Html tag. And then we're going to be the Ajax call to go and Fitch the values from the database and bring them back here. So to do that, I went to see a dollar sign dot get JSON. So this is a jQuery method That's allows me to call a URL. I was going to put empty quotation marks are there for the URL. It's also allows me to pass in data. So in this case, I need to get the models based on the mic ID, the parameter name. That's I'm going to use this mic id colon. And the value and passing it is Meek ID. So this is the parameter name. This is the value I noticed when I highlight this, it also highlights the variable. This is the value of whatever value came from the change event. That is what I'm passing over to this method. Then I have a comma, and then this function basically says, when it is successful, I will do this. And it takes, or it has a capacity to take a parameter called, I'm calling it data. Data here would represent whatever came back from the server side call. I'm going to leave this shell of, of a function here. Inside of this area is where we're going to do with the magic of filling the slope. But this is the basic template. So we have a URL, which of them putting it where passing over the make ID value that is going to be used to filter the list of models. Then when we do get, but then they self models, we're going to be implementing the action in that area. Went to pause here for a bit. And I'm going to jump over to the code file for this create. And what we need to put in here is a method that will actually be called whenever the change event occurs. So remember that ajax allows us to make service. I had calls from client side code. Here. I'm going to put in what we'll call it another handler. So remember that these methods are called handlers. And this one is going to be JSON results. Public AsyncTask returning JSON result. And this is going to be on, on get. So remember that I was saying that you have on get, that's a keyword on post, That's a key word. When we want a custom 100, I am going to say on Git. And let's call this models, or you can even call it a car mobilised if you want to be explicit. So on get car models, this needs an integer which would be Meek ID. That is the parameter that we're seeing we're going to be sending over. We need to receive that value inside of the parameter there. Then this method needs to return a JSON results. So why do we need to run the query? And two, we need to attend to do some results. We can do it in one line, I'll do it in two just to show VAR models would be equal to context dot car models. And then it's easy enough to say it to list. So you see that the two list async is just going to return every single thing in the list, which is what we've been doing here, but that's not necessarily what we want. We want it filtered. So I need to inject what we'll call it a condition or where clause. I have to say dot where. Then we put in our Lambda expression. So q is my token this time. And I went to see where the column of MC ID matches the value that was passed in through the parameter. After we get to all of those, then I'll just say return new JSON result with the data of modules. What this will do is actually take all the database objects, the data from the database storage instead of models. And then this will just return all of that in the form of folk called JSON. This is complaining because I need to, I'll wait the call to this method. No, I have an idea of the path that I need to call in order to get the data back to the JavaScript, I can now say getJSON, your URL, or the path you should call. It would be slash cars, slash create. I guess that looks familiar. It's flashcards would be the cars folder slash creates would be our Create file, but our Create file or create method which has the on Git and the on post also has on get car models. And this is our handler for that situation. So I have to see. A slash guys slash Create. Then I'll pass in a query string in the URL to see the handler you're expected to call in the Create Page is equal to car models. Notice the naming convention over here. It's called On get. That's a keyword, that's a key expression that Razor pages is looking for, but the method itself is called car models. I'm seeing your handler is car models, so I don't have to put on the guitar, the onPause part. I'm just seeing called car models. After doing all of that, we have the URL set and we have the data, or at least what needs to be possible as a parameter we're expected to get. But this data, what I'm going to do is loop through the data and filled the drop-down list manually. The reason I would've put this line in is that every time I make actually engine the mixed drop-down list, I want to reset. So by just calling this line is going to empty out all the HTML and it's going to sit only what I put here as the HTML. No, I need to having fit to the data. But in the rest of the HTML, dollar sign dot each is a way I'll seeing for each in JavaScript. And the collection would be coming from more variable here, data. So data will represent the new JSON result that is returned. For each. Basically objects in the data execute this function where I get a key and let's call it a value, a key and a value. And then we open and close that and semicolon. So I don't forget. So in this forEach method, I'm basically just going to define what an option should look like. So var option is equal to and I'm going to see dollar sign option. So dollar sign, open brace option, open entrails option just like the tag. So we want that upsilon tag there. I'm going to add an attribute. So remember that an attribute that is very essential to a drop-down option would be the value. I'm adding this attribute and I'm going to tell it that it's value is the value dot d. Alright? Because remember that when this returns the list of models or a model table is going to give us back the ID courtesy of the base domain entity inheritance is also giving vodka name. Yes, it's given about Meek ID and list of cars. That's fine, but we do need those really need the ID for the value and the name for the display. I can infer that the JSON result, which is just returning results of the same to us or result of a bunch of objects of the same class that we just looked at. It is going to definitely have the value section, an ID field. And then I went to add dot txt be the value name for each option, for each value or each thing that came back through the data. Get the value. Then build an option where you're putting in the value as the attribute and the text, which will be what was in-between the open and close. The section that says select model, that takes to be a valid name. After I've built an option, the next thing would be to append it. I'm just going to see models dot append up into, but just append option. So append know will add to the end of whatever is in there. So when I say dot HTML, it will empty Totally will reset it to whatever value I want here. If I wanted it blank, I could just say your HTML is no blank. Your ischium, there is no adoption. However, in this case, I don't want to clean the toilets. It's already cleaned out with the default. No, I just wanted to append the other options, the default. Now with all that done, what I'm going to do is introduce a little method here that I use to debug called console.log. Whenever you are trying to do your JavaScript or jQuery and not quite sure if what you're doing is working or what values are being passed are being set. You can always do a console.log which will print to the console area of your browser, showing you whatever it is you're printing out. So I went to do a console log for the Meek ID just to make sure that we're getting by the cart's value whenever there is a change. And I'm also going to do the console log on the data right here when the JSON call is successful. Because then you'll see what JSON really looks like if you're not quite familiar with. What I'm talking about when I see Jason, let us state as far as being an aldose to control F5 or rather I'll do it in debug mode, set a breakpoint right here so we can see exactly when that method is called. We can go ahead and get a better understanding of how Ajax works. All right, so we're on the page millenia, see here one, there is nothing in this drop-down list because one, we removed our ASB items from it. So ASP items, so the mic, but for the models There's no ASP items. So even though we call the database in the background and we load initial data, we didn't tell it where it should be getting its reactants from into. We also removed the default option from this linked list. So we're getting a blank dropdown list. Make is fine. Now when I click Toyota, look at what happens is jumping to my break point. That means the Ajax call is successfully finding the handler. I'm just going to jump to the last line so that we can see what is in models. You see here, that's, it's actually got the one Toyota model that is in the database. That's all the data that is returning everything in the database. So we could refine this a bit more because we really don't need all of these things. We really just need the mic ID and the name. Alright, but that's fine. Let's just go ahead and continue or sorry, we just need the ID and the knee. We don't need to make any sorry if I just hit F5 and allow it to continue. Now you'll see that default text being loaded in. One unchanged. It went ahead and set the HTML. And then two, it made the Ajax call, which then retrieve this stuff. So that means under that I'm going to see supra know when I talk about console log, if you right-click go to Inspect Element or heat if 12 and click Console, then you will actually see the console. It messages being printed here. This is an error about trying to load the font awesome stuff. So that's minuscule at this point, what you see here that the console is logging the mic ideas. One, if I change this to Nissan, you see it's Tool. If I change it back to Toyota is each one. So each time we made the change, we're console logging, we can see what value is being chosen. Under that. You'll notice I'm far more complex looking construct and this is what JSON really looks like. If I expand this, that is what we call a JSON object. Json is JavaScript Object Notation, which is very, very popular standard for transporting data across the web, http right now. In this case, what it did was to take all the data from the class and serialize it into key-value pairs. So the name of the field and the value that the field we would have. So that's why you see name with a value of Meek ID with the value make, et cetera. So it's the same kind of constraint that we just used right here when we were making the call, that is this one. Notice key or a parameter colon. And the value just since I'm using a variable, but in this case arose in the literal values. After getting that object from the ajax call, we're able to know just access the individual values or the values by their keys. It's, it's an object and it's also like an array. It's an array of these JSON objects. If I had multiple, tell you it does in the system. So let me just go over and create a few more and models. I just created about two more Toyota's in the system. So look at what happens when I touch you answered Nissan, but I am changing buck to Toyota norm seen that there are three Toyota's in the system. I didn't pause or anything literally, I just went over created them. There are no in the database. Every time it hits the need to busy, it's going to get back the newest values. And there are JSON objects. So we're seeing each one of the cars in its own JSON representation and being represented right here in the drop-down list. So that's what we'll call a cascading drop-down list. The persons who requested this feature didn't know that they wanted a cascading drop-down list. They certainly would not appreciate the level of effort that goes into creating such a construct. However, as developers, we're always going to be given the requirements and it is up to us to find the best solution. So in this case, JQuery was the easiest solution for something that, like I said, jQuery or JavaScript. That's not something you're going to always write necessarily, but it does definitely come in handy when you have certain situations that need quick and clean solutions. Just by way of clean up, what I'll do is just remove these console logs because they're really for debugging purposes. You don't want to leave them in your code. Because when your application goes public or the beaver might see it and wanted to get inside information or potentially sensitive information in their own browser, console logs for your website. You don't want that. After you've debugged Daniel, fixed it and you know, it works. You can always go ahead and remove your console.logs. That's really it. So one other clean-up activity or a few cleanup activities, starting with the FID that I really would want this defaults to be there at all times. So what I would do is also replicate this. And even then you could put it in a method. But what I'll do is put this outside of our mix change function. So that means as soon as the page loads, we will always be sitting this option. That's one option. The other option is that we just put it back when the page loads. We just have the default option here that says select model. But of course it has no ASP items, so it's empty. That's the only option that would be there. Either way when you change, will always that value before it appends the values coming from the database. No, outside of that, another clean up that I would want is in the Lord initial data. I don't need to call the models. If I'm going to be loading them dynamically, then I don't need to call this query when the page is loading. So that's one list query upfront. And that's just going to lead to a snappier low time. We've done all of that in the Create. Let's just go ahead and meet the same changes in the update. And then this is where it can get a bit tricky again. Am I going to repeat all of this? So right now, what would, we would be inclined to do is just copy this, put over into update and copy this, sorry, this JSON result method and put over into upbeat. I would agree that maybe this JSON results method needs to be duplicated. Okay, I can accept that. But when we come back, we'll look at the best way to actually share the code between the updates and the create, such that if there's need for maintenance, once again, there is one or very few points of contact and thus reducing the maintenance efforts in the long run. 22. Add Cascading Dropdown Lists with JQuery - Part 2: And we're back. So in this lesson, what we're going to be doing is modifying our update to be able to do the cascading drop-down list. And what we don't want to do is repeat all of this code between the two views because let's just muck truck. We have too low the model drop-down list to repopulate each time the mic drop own list value is changed. That obtains on the Create page. And that also has to go on for the update page because it's pretty much the same form, the same thing as expected. Now the update pH has an additional requirement where when we see that we have the mic and that value would already be provided when we select a car to update or to edit, we would select a car. The pH or this update form is going to load with all of the values for the car. It's going to load with a value for the mic. But then this drop-down list by default is going to be empty. So remember that we're moving, the items will have to dynamically loaded. And I also want to make sure it's loaded with the, only the models. That's our relative to whatever mic was selected. So if this was Toyota, then I should only be seeing the Toyota values when the edit page is loaded. So that's another modification that we're going to have to make sure that we account for when we write our code to meet this script shareable. Firstly, we're going to have to put it in its own file. And we discussed that from the earlier days when we talked about cold to me, the JavaScript shareable across multiple files or pages, right? So the same concept applies here. What we'll do is go to our dub, dub, dub root. In our JS folder, I'll just right-click. And I'm going to, if I had a new JS file, so just Add New Item. And frankly, I usually just choose anything here because I know the file extension that's at once. Instead of trying to find exactly the one. And you can just search over here and you can see JavaScript. So you get JavaScript file. That's okay. But ultimately what you want is something with the extension dot js. We'll just call this one cascading models script. Guess kidding. Sorry, let me get my spinning red cascading model's drop-down list script. So I'm naming this explicitly because I want it to be very clear what the script file is going to have. Cascading model's drop-down list script. Press Enter, and then it will generate that file for us. This final column is empty. If you use them another template, just clean everything, alter the farther. The most important thing is that it has the dot JS as a file extension. Know what I'm going to do is take all of this, coat it, and then I'm just going to paste it inside of our GIS files. So that is simply enough and they know that we have the js file. What we will do on The creates and the update pages will be to replace the script tag with the SRC component. It just says Script SRC is equal to an intelligence will help you to fill it out. You just control specifically don't see any prompt. Slash cascade Cascading model's drop-down list script.js. You can just copy that and make sure you put it at a similar place on the update page. Note, since most of the modes we're making no art to Quito to the update operation. We have to make sure that the update form looks just like the create form. A part of that is to make sure that the same controls are, the corresponding controls have the same ID values as seen on the create form. An update makes sure the mix has ID equals mix. And make sure that the model has ID equals models. Just made those modifications. And then let's jump back over towards JS file and then continue or work. Now a few things to consider. One, yes, when we're creating, it's fine because we've seen it work. Everything starts off with the default values. And then when we change the mix, it's expected to go ahead and Fitch the new values. It knows the path. So we don't have to change the buffer because it's already exists in the Create page. The updates can actually just call that same path in the whole JSON file requests or other. And that should be fine. We don't have to modify any of those concrete things. However, we have to consider that when the form is not blank, like in the case of an update, there's going to be a mic ID present upfront. With that make ID, we need to make sure that we populate this list upfront. We can't wait for the change event on an update to have these values present. That's, those are two factors. Another factor is that we need to make sure that the value that was selected by the user when they created. The vehicle is the value that is presented. So while we're populating all of the options, like we have maybe Toyota, we have four options for Toyota. Only one of them was really selected. We have to make sure that that is the one that is visible to them. As we've seen on the update page, the drop-down list will always show the value that was selected during creation. So we have to make sure we replicate that kind of logic here with a few tweaks. What we will do one is take this declaration of Meek ID. I'm going to put it above the scope of the event. The event happens here, makes not changed function. This function is our event. I won't make ID to be global to that byte. So by doing this declaration at the top of the file with no braces are owned it or anything because our scope is really open and close briefs that event dysfunction is within the scope of this change event because the bracket opens here and it closes here and everything inside of that is within its scope. So by putting this old set of, there is no scopes are owning this variable. Every function and every other bit of code that we write can access it at will. So that's fine. Now that we have done that, what we need to do is also meet this reusable. So right now it is bound to the confidence of the change event. I don't want it to be only called when there's a change event. I wanted to be called automatically when there is a load event. Also, what I'm going to do is cut this. And underneath the change event, I'm going to make a custom function, just read Lord function. And we're just going to call it Lord models. I'm just giving it a name. You can do what it will be doing for us. And we're just going to say Paste. Now that this is in a method, I can call it that well, so I can see whenever makes this changed, I want to load models before I can load models, however, I have to get the new value of Meek ID. So we're just tweaking here. Remember that this object really refers to whatever set off the event. Now, this is outside of the events, so it can't be this while we're here. So I'm going to copy this line and see when this event is triggered, the value of this control that triggered it, and then everything else can flow. No problem. However, when it's global and it's being declared after manually say get me the control with the ID mix and get me the values. So I'm just pointing those out based on where you're doing the same lines of code, the way you access it would have to be different. I mean, we could have accessed it like this inside of the form shown, so that wouldn't be a problem. I'm just showing you how you can reuse the syntax in different ways. So we have to access it by its name here, but then we have choices inside of our click event. So with these modifications made, I'm not Lindsay go any further. I'm going to just go and test and make sure that the create steelworks as we lift it. Testing the Create, I'm going to change the Toyota and I'm still seeing Toyota's come up, Ferrari's. So everything works in the Create. So with those minor tweaks, we have routine and all the functionality that we would have left with last time. No problems. So create still works, cleaned out some of my records, especially those with our funded models and so on. I just cleaned up the database of it so is get back into it. So no, the objective would be that when we click Edit, we see Ferrari coming up. But what we're not seeing our two models or the fact that it was spider. Remember Ferrari spider block. When we click Edit, we see for RT, we see black, but we're not seeing spider, we're not seeing any values here. So we need that to happen automatically. Of course, when I do the change event, it will happen, but we don't want to have to wait on the change of n for that to happen. Let us modify the code accordingly. And what we'll do is call Lord models on. On starts. As soon as the script is loaded, we want to load the models automatically go into one, get the Mecca ID. So it's automatically when the edit page is loaded, this script will get the value here. Then load models would say, go ahead and meet the JSON called policy in the Micaiah idea and getting the options. All right, so let me just distance see if that made a difference. We just refresh the page. And if you look let me just refresh again, building those refresh properly. So I'm just refreshing for Ari's loaded and if you look, you'll see spider in the list. Exist. Similarly for the Toyota, if I just click edit while it says select model, it does have all of them in the list. So at least that part is working. No, we needed to make sure that we're selecting the correct one when loading the drop-down list. Here's a cool way that we can pass the value coming over through our binding and from the service side over to our client-side script and then use it to inform our decision. In this script tag, we can pass in value parameters right here. I'm going to say module ID is equal to. And then in quotation marks output to add sign, model dot car dot car model ID. Right here. I'm just passing over our parameter when you call this script, meet this value available to it. And that is what it should be called. Nice and cool. So the at sign once again, is used as part of Razor syntax anytime you see it, That's how we can access C-Sharp. You can use that at sign and if statements here for loose, whatever it is, we've seen it multiple places, but this is how we can actually use it to our own advantage. We want whatever values there and we're mixing it in with standard JavaScript syntax. Knowing the JavaScript file itself. What I can do is say vd model ID is equal to document is a static keyword that represents this document that I'm in, or the document, meaning the page. What we always say document.ready when we want to initialize our JavaScript or jQuery, rather, document dot current script and get attributes. So attributes would represent this parameter. We're calling it by name. So we're seeing that attribute and we're storing whatever value was possible with that attribute inside of model ID. Then underneath the option, I went to introduce an if statement that says if the value dot ID. So remember that when we're getting all the cars as the data or from the JSON call. This runs the query against the Meek ID and then it returns all of it in the form of the spherical called data. Then we're iterating through data and seeing give me each key and value pair. Key would be the name and devalues what we really want. Creates an option variable that represents an HTML option tag with the attribute value stored in the valley dot ID. And takes that is presenting the name that came over with that value key peer. Then I'm seeing if the ID of the current option that you're building, if the idea of the core invited that you're evaluating or other much is the model ID. Then that option, add a property, give it the name selected and choose. So prop, an ATTR or attribute can look very similar. They kind of do the same thing, but I'm just showing you different ways you can write similar code. Here. I'm just saying option that property, Add Selected true. Then we go ahead and append it. With those changes made. I'm just going to save everything and then we can jump back over to our edit and we'll identify, refresh it, refreshed itself and seats work. I went to go back to List Toyota Supra. When I click Edit, super is automatically loaded even though the list is full, supra is the one that is selected. If I go back for our spider is so into the, show me spider. So it went Fichte all of the models from the JavaScript and then evaluated them and saw that, that one much the one that was selected. If I just do an inspect element, you see on that option, it has the value bought the property was set to select it, so that is why it floated to the top. Alright, so that is basically all we need to do to get our cascading drop-down list working for both the create and the update in general, that's the concept behind, I guess getting dropped on its anytime you're using a system where you select one option and that option influences the rest of the form or the rest of the options. This is all they're doing. They're doing is watching to see. Did you change the value in this drop-down list? Ephesus carry all these commands. These commands could be hiding parts, hiding elements of the form. In our case, we're completely rearranging the elements of another part of the form. Whatever it is you need to do. It is right here at your fingertips. These things are there, canada difficult to memorize and if you don't use it a lot, you might not necessarily have it on quick, rapid fire. Recall every time you need to do something that is but the reality is that once you understand the concept of whole JavaScript can help you to meet dynamic webpages and hold they can bring towards fruition your idea or a vision for a page or a form or whatever it is. You just need to go there and research HomeAway, do this and break it down into smaller tasks. Yes, it was a big task. Thinking about all one dropped on this is going to change the risks of it. But we could easily itemize and say, okay, what are the scenarios we need to account for? Who do I have cone for that scenario? Scenario number one, options must be available at all times. For the edit. And four to create, both rely on the same piece of code. Instead of writing these two places, I just put it in a method and call the method two places. So something changes a bolt hole we're going to formulate or options or so on where you just have to meet the Chines one, please. So these are things that you just with practice and exposure, it will become natural and second nature to you. 23. Fix Data Label Displays: All right, so we're nearing the end of the basic parts of the application. We've set up a crude, We've done some cool JavaScript stuff. No, it's really just about beautifying the application. The first portable beautifying this application to me would be fixing the labels. So we kind of put in some effort to make sure that these labels are set properly on the list of cars. But then if we look at mixed models, colors will make is only showing the name of the mic. And then if you look at others are seeing date created as well as on the colors. So I would want to probably either fix this, make it spaced and more human readable, or just remove it because I don't think are users really need to know at this point when it was created. Date created is more for a system auditing than for user consumption. We can go through and hide some of these. Another thing that I would want to prioritize would be on the forums for Alice create car. We were seeing that we're seeing make IID car model ID, caller ID. Now remember that these ID values are more for this system then for the user. So the user is going to come here and wonder, what does that make ID, but then they're seeing names. Instead the labels should see see meek or something car model color. Instead of Meek ID, that license plate number, that to me should be a bit more human readable. I think it would be nice to put in some validation to make sure that no two vehicles get the same license split number. I think that's detriment of data quality. So little things like that would constitute the cleanup activity. Let us start off with our interfaces for the model and the color that have deed created. That's simply enough. We can just jump over to those pages are those It's pages. So for the model, I'll jump over to the index page and I'll just remove the column that shows the date created. I'll remove those two columns. Going to do the same thing for the colors index, remove it created, and remove. That. Looks good so far to me. At that point that activity is good and all for the create cars and update or four forms for the cars where we had a model ID. You see here that it says Lear SP Sir label, ESP dash for car model ID. All right, So we already looked at how we can change the display name for the index where it's a display name for. And we said name is pollster show as the word model instead of its default name, name. That's simply enough. All we have to do is everywhere we would have had that ID value. We just make it know that it's supposed to see me. Here when we're creating the model, we would have had the drop-down list for the mic ID, same principle. We just give it the display name mic, so that drop-down list will know LC MC instead. So if I jump over to the model, I just made a cheat and say that's the update. The application. I'm running without debugging. But when I go to models and click Create new, There we go. It's not saying make instead of Meek ID. So let's look at cars were uncharacterized form it said make id, car model ID, and color ID. So what I want to do is go over to the car class and over Meek ID, I went to see your display name is equal to MC. For the color your display name is equal to color. For the car model ID, your display name is car model. So when I save all of that and go back, it's going to automatically refresh and you see everything now it looks a bit more human readable license plate number. I'm going to give it a display name. And that display name is going to say license space split space number. Here. If I wanted it to be a bit more sophisticated than just year, I could see your display name is manufactured here. I'm just showing you that when you see these nice clean interfaces, this is all they're doing in the background. Dotnet makes it so easy for you to kind of meet these changes in the background and have it manufacture here. It makes it so much easier for you to just be consistent across your user interface with their labels and how everything looks. So that's really it for this particular activity. The next major activity for me would be to kind of change the buttons or have the consistency with our buttons. So we went through that major overhaul with cards where we set up these nice clean looking buttons for the create, new, for the edit, for our Create, or a buck to list for the edit page, save or a buck to list for the details, idiots or a buck to list, we have all of those. But then we introduced other pages that will just brought us right back to the default stuff. What if we wanted to actually change, hold these look, or rather it's easy enough to change or they look because we've done that. We see hold to change how they look. But what we need to do is to make sure that they are all consistent. Consistency is key. In web design. You want to make sure all your pages have that common theme behind them. What we're going to do is look at whole weekend these buttons and put in more reusable forums. Because if I had what I do have 1234 different places with Create button. So I have a Create button on the list of cars, one to be on the list of mixed models and colors. But then what if I wanted to change the general design from a plus sign to something else or something or on the button, I would have four different places to meet that change. When we come back, we'll look at how we can kind of abstract that's Alt and use won temperate across all pages. 24. Clean Up User Interface: The last time we were here, we were treating up our labels nowhere coming back to clean up all the four buttons and the general layout of all our pH's, the lists and how everything flows. We're talking about having a general template for hole or button sections. Look. In this lesson, we'll be looking at what we've got partials. Partial is exactly what the name suggests. It's like a part of a page. We're already using partials because our views, these view PFAS are technically partials because it's only part of all that is required for an HTML page. And then what we're doing is just it randomly or not randomly, sorry, dynamically rendering them inside of the particular section of the overall pH that we want. So this is our main page and this is where we set all the global styles and everything fine. But then we're rendering the partials based on where we're navigating, we show the partial to make it look like the change. The pages are actually changing when all we're really doing is changing the section inside of the render body. Now we can bring that concepts don't a bit more to the actual page. And that's what we're going to be doing to get the index buttons. Right now, I have completely studies index buttons for the cars index page. It's easy enough to just copy. Jump over to car models, go to index, and it replaced the buttons here. That's easy enough. Then once again, it's easy enough to do that for every other page. Because really and truly the buttons needs to look alike and our routing is fairly consistent except the fact that we use the default scaffolding here for the edit for the car models and everything else on where change that to update for the for the editing for the carts. I'm actually going to undo that. It was just bringing home the point that you could change them. To rename a file is pretty simple. I'll have to say is renamed the top file, the code file will also get renamed. But then another consequence of that is that I like to keep be consistent with the name of the model somewhere to change this from opiate model to edit model and use control dot and do I renamed refactor through and through. And then any, any path that would have led to update that CSS HTML needs to lead to head. It would have by default. I was just saying that to say that if we're going to be consistent, we need to be consistent. You can't name one it an India, China, and other one is change and so on. It makes it harder for you to actually be consistent with your code. We are going to be changing the buttons for all the indexes. But once again, I don't want to copy and paste the code. What we're going to do is in the shared folder. Shared the purpose of Sheard is that the different partials are accessible across the application. In the shared folder. We're just going to go ahead and add, I'm going to say new item. And from the listening would to choose razor view. If you look at the difference between arrays of B-trees of view, the extension is the same within the description says that there is a page comes with a page models. So what we've been using upon to know IRI. So pages where we get to CSS HTML and the CSS HTML. However, the raise of view is only going to come with the CSS HTML and that's fine. What I'm going to call this partial is underscore index partials, sorry, index buttons. When naming convention lead with the underscore. Consistency is key. Underscore index buttons. And it just so it's very clear, this is a partial index bonds, partial z of two crews, the leading underscore and the financial ends of the word partial. So we can go ahead and add that. When we have this raise of view, we need to specify a model. The model basically represents any data or data type that will govern the type of data that is accessible on this partial. In our regular ease of use would've had model at San model. And you would see that they are using some complex class types. And that's why we can do some wonderful things accessing data and manipulating it. However, all we want on the pH are the index buttons. And all the index buttons really need that would count as dynamic data, would be the id value that each page would have our need to generate for each item. So all I'm going to do is say, Saying model. And I'm making it an integer because we're expecting an integer value as the id value. The buttons or the code that I'm going to use for the buttons will come from the car because these are the buttons that we've designed nicely already. I'm just going to go over here, copy them. And I was seeing that everything needs to be consistent. So we have changed the edit, update to editing the link, and we have made sure to change the page name also so it's no longer update, It's not edit that we everybody shares the same basic files or file names pretty much across the board. Someone to copy this, put it over instead of the partial. Then you're going to start seeing red lines appearing where item.name DID was because I was seeing okay, I don't see any item or any variable or object on the Pease named item. I don't know what, but remember that our model is the integer which is basically representing item delta ID. So I can just say at sign model, because model is just going to be an integer. This was close to show you that anytime you need data on your page or a partial, you only need to defend a model and use your datatypes to your advantage. Model and model. Edit details, delete. All of those are on our partial on the page that we would want. And I went to test it on the car speech first, where we want to include the partial, you have to say at sign because we have to read some C-sharp and we're going to wait or HTML helper. And we have partial a sink. So anytime we're using an async, we have to precede with a weight. Then this method takes two parameters or it has several overloads we're using on overload that's going to take won the name off the partial, which is index buttons partial. Then we're going to also give it the model. Model is generic. E can be anything. It's not making the assumptions that the model has to be anything. I'm telling you what the value I want to pass over is. And it will figure it out when it gets to the actual partial that okay, the value provided is the type of model it's expecting. If I said Interior and I provided a string, it will not load if I say Juan data value type and they provide another data value. So if I want, if I say the mode is the data type, but provide a value of a different datatype. It will not work. That is just letting you know it's very generic but strict enough to know that what you gave me is not what I was expecting. We've made that modification to the car's speed. If I Control F5 and look at it, I'm getting 500 errors, so I'm getting uninvited exception and, you know, I don't shy away from arrows. I want us to see what the error is. In this situation, we're getting some insight as to where it will look for an int, for a partial. So these are legal places you can put a partial such that when you just see this is the partials name, it will look for it in these places. It's looking in pages slash cars slash index button partial. No, it's not. Therapy edges slash pages slash shared slash there and views slash shared slash the name. We know for sure that we put it in pages slash shared index, partial. But then I said In button partial in the code, when I call the buttons, That's my spelling error right there. Just go ahead and modify that, save and then come back and refresh. And nowhere seeing two sets of buttons. So our code is working or partial is working. So now let us prove even more so that the partial will work. So for mixed models and for the colors, I'm going to take that one line of code, one line of code. I'm just going to put it on all the other indexes. So if it's on cars already, let me put it on index For four models, some wood to put it on the index, four colors. I'm going to put it on the index for me. Then when I save and control, refresh each of them, you're going to start seeing these links appear. Anything that's not refreshing, He's because I didn't save. So let me go back. See nodal buttons up here, nodal buttons up here. So you see with very minimal effort, we have sheared these buttons. Let me see if they still work. If I click Edit, it navigates to the edit page. If I click Details, it navigates into detail. Sp, it will do that for all of them because once again, consistency is key to navigation. Properties are the same everywhere. They're all looking for the ADA, same construct or values. But then relative to the routing mechanism internal to the folder for a car models and for cars and for each of the other ones. It knows where to go when it is clicked. But it's one baseline code. What I can now do is remove the default ones. I'm just going to go through each of the indexes and you're going to see a bunch of cleaner this looks, we're reducing three lines of repeated code. And in the case of the cards, even more lanes. And I'll just remove that commented line. And that looks much better. Know everybody's on the same page with the buttons. Know earlier I would've said, are encouraged you when we're doing the other crude tool, try and replicate the whole delete functionality and the delete button with the click on the form and everything across all the other pages. Know if we wanted to share this this bit of code across the pages, what we would have to do? Well, we can't really share the form. I wouldn't recommend trying to shear the form. And we definitely can't share the handler, but we can share the script. So I'm just going to create a new JS file. New items, sorry, and look for JavaScript. And this new JavaScript file is going to be index delete button script. Then we can put the, let me just go back to the code here. This entire function, I'll just cut that, place it inside of the index delete button script. At this point, we actually do have a few opportunities available to us because I didn't say we shared a form, but let me evaluate let me just close everything that is not necessarily needed at this point. In the form, I am being very specific when I say the name is car ID. It's not necessarily car ID. I could have easily call it record ID. Record idea at this point is a far more generic name than just car. Instead of looking forward, only car IBM went to look for a record ID. And I'm going to say Sit the record ID to be equal to whatever data IDs on the button. So remember that everybody's using the same template of a button. So once they click the button, it's going to have that ID. We can use the same form, sit that on a weekend, just submit that delete form. I can now create another partial. You see, so let me, before I create that partial, Let me see SRC is equal to G slash index button Delete dot js. Just making sure we have that. This form can actually go into a partial because I'm putting it in a partial because I don't want to copy this form across all the pages and if something changes with the form, we have to do it all over again. So it's better to just put it in a partial and heavy to one place in this year and I went to have another razor view. So go add new razor view. Soon as I see it. There we go. And on the score delete form or index, delete form, partial, sum, naming it well enough that I can see the name later and figure, oh yes, that's what it was for. This partial doesn't need to take any dataset. I don't even need to give it a model. Always going to have is this delete form that's looking for a handler on whatever page it's on called delete is passing over some named named record. Call it a record ID or a named variable called Record ID. That's all this partial is four. On the index page, I have another way to include partials, which is a much simpler way where I just say partial name is equal to and the name of the partial at hand. Instead of typing it alternative scans for the error. I just clicked it, press F2 to rename copy the name and paste that it's working smarter, not harder. Then I can take this block. And while it's on the cars index page, I can put it on every other index page. Quarter usability. So now the forearm is here and the script is watching the delete button from our buttons. So I can just go ahead and put that on every index page. All right. We're nearing there were nearing there. Once again, we're promoting code, reusability and templating. We want to put in all of this effort upfront. You may take long know, but in the long run it is for a good cause. Know that we have the Delete Forum and everybody's seeing record ID. Let me go to the code behind for cars, since this is where it all started and then we went to control and motor does collapse everything. And then we have our unpause delete taking car IDs. Instead, I went to see a record ID because remember this is what the name is going to bind to. I'm just taking record ID and I'll just renaming refactor throughout the method. And this one is looking for the car and then it's going to try and remove it and redirect to the pH fame. I can take this method and this method ES, we loved. You repeat this method through and through. We could theoretically make one result page that has all of these generic methods and recall them. So like even with the cars to get the JSON result, instead of having to repeat it on the create and update, I could put it in one generic handler that we just make sure we call that path from everywhere. But that's fine. You know, while it sounds like a good idea and it sounds logical, there can be limits to how much you want to make everything you're usable engineering. And sometimes your context will determine if you need to go that far. R-naught in this context, I'm not going to go that far with this particular method. Instead, I'm going to let each index page retain its own implementation of the deletes because different the different pages or records may have different requirements for our delete, right? So like for instance, models, if I was to delete a model, then I would probably have to Elite all the cards related to the model before I can delete them model. The logic inside of this might be slightly different. In this situation, the delete here needs to look at the car models and delete the car models. So anything that's at car, I'll just rename the car model. That's implementation. That delete is present on the car models page wherever it's on cars already. So in the colors, it's the same principle, we just add that and record ID stays the same. I rename this to color. And we're looking in the colors table through and through. And then we do the same thing. But by no means least for me, where we changed the table to mix anything that said color or whatever else you may have been copying and pasting all this time. Noses mix, know each index page knows it has the delete method looking for a record ID. Record ID is coming from the form which we just put in a partial. So every one of them would be looking for that delete form and sitting record ID to the value. And once again, the script is no sheared across the board. So let me go ahead and test this. We select a mic still to both. List is not populating, that's suspicious. So let's go ahead and inspect element, look at the console and then we're seeing this ERCP cannot read property, get attribute off null soul. I believe that error has to do with the fact that we are passing, in our case, we're getting the model ID to be whatever this attribute is when it's passed in in the update page. Sure enough, for the ATPase, rather, we are passing in that attributes, but we did not do it on the Create page. What I've done is to introduce that attribute in that script on the Create pH where I pass in model ID is equal to 0. That is of very little consequences considering that at the time were creating one, no data is presented. So that's why I cannot use car dot car model ID because car is empty, It's not. So we'd end up with the same knowledge exception just under C sharp side. Instead, I'm just giving it a default value of 0 because we really don't need it. No extension of that goes to, or an extension of the modification requirements goes over to our script. If we go back to the script, let's just evaluate exactly what's happening. When the script is loaded for the first time, it's getting the medical care that's presented. It loads models, and then it gets the attribute, and then it performs the JSON. But look at this. Every time we're going to be changing the mix, we're going to be calling load models, which is then going to try and get the attributes again and then do the same thing. We really don't need the attribute more than once. Really only needed the first time the pH loaded. Because after that, we don't really care for what might've been selected. What I should do is caught this and put this global script is running, get the mic, get the model ID, then Lord models. Then it does that. When mixes changed, we get to make IID. We reset the models HTML and we load models, which does the Fitch. This really only needs up in one time. So that's another reflux so that you probably want to consider because I believe that this error would have broken door cascading style sheet for every time the value is changed. If you spot that one before me, then kudos means you did more testing than I did. These changes made, Let's jump back over to our web application and go and try or create for the car again. And then I do Toyota, and then I see, Okay, Nissan and Ferrari hokey are cascading style sheet is Buck. Let me go over to the edit and make sure that bindings to worst if I change the nuisance and it comes up for our spine. Good. We're in the process of testing or crude Toyota Corolla block. This one is a 2001 less-than split number, and I just added three other ones just to speed up tool addition process. I'm going to test the delete. So we wanted to make sure that the delete functionality still works on our car speeds. So delete, we're getting our suites alert, that's good. If I click Okay, it's deleted. That works for us. That's good. Now if I go to the other pages, I'm going to create a test here because I lead the other ones. So that creates still works, That's good. Does the delete work or look at that? The same suite alert is coming up. And if I click Okay, it's calling the delete farm and redirecting to the page and everything perfectly. Now we see how we can put in. Sure we'll code someone to delete the higher from the module list that works. Then I went to create a new color. We still have the deed created, so that's another clean up activity that I would have overlooked where we need to remove the input field for deed created on some of them. But we have the test and the Delete works. Just like that. We would have set up some partials to make sure that the buttons look consistent. So that same concept can be extended to even the Create book or Create button here with a plus sign. Although those look clean, but what if we wanted all of them to look the same way? So instead of creating it or whatever enemy in this style for the create button is not the most bit of code, but once again, it's a matter of hole. You want to restructure your application as much as possible. In this situation, you probably, you probably just meal key and content with just copying and pasting the Create button maybe of different ideas for the different Cree blends on the different pages. But ultimately, I would probably try and put that in something that is reusable, especially since this one doesn't need any data. It's just a button or an anchor tag that has that top kill Partisi ASP, dash pitch. Split ahead and did the editing myself. I didn't want to walk you through each one because like I said, whole granularly get with the templating and the buttons and share ability. That's up to you on your tolerance for such an activity. I went ahead and did it and I'll walk you through it just in case it's something you really, really would be interested in doing. Regardless. I'm just going to close all tabs and we can just look through the shared site, created additional ones. So we did this one together, index buttons partial, we know what we know and understand that we pass in the data as an integer and we can access that data through or keyword module. Now, for the Create button partial already it will stay the p tag with the create button. And this is coming from the one that we did together for the cars. And then on each page, I've just done the other way of referencing the partial, which is seeing partial name is equal to that. So because there's no data that is needed for the Create button, I don't have to put in any model or anything like that. You can also include partials like this one. They're just like static HTML. And generally speaking, when they need data, you have to do it like that. Alright? So this static HTML looking Target, I just put that in the car models. I put that in cars index anywhere I needed it. I just put it wherever they created. What was I just put the partial. Once I get if I wanted to change the design, I just go and change the design one place and everywhere gets affected. That's the create one. I did it for the details and all the details buttons would have had this div with the anchor tag to go to the edit page. And it would've taken the route ID in the form of the record ID. And then we add the buck to List button. That is why this one required a model on any details page that partial was used? I would have had to wait. Partial async called the detail button partial, and then I just pass in the ID as required. Another part of the cleanup was that I removed the date created fields from the create forums and from the index and so on. So that was another part of the cleanup that I kind of did off-camera. But once again, be free to be creative. Feel free to be creative because it's your application, you know best, and your customers are the voice that you need to follow. So do what you feel is right and you can do clean ups that, or make modifications to your interface that I am not considering are doing to mine. So the other one would have been the Edit buttons, which are straightforward, strictly HTML. These would be the Edit buttons at the end of the form, the one to save, the one to go back to List. So on any edit form, I would just see partial edit buttons, partial. Just put that and remember that the form group I just did the whole div, the buttons and put inside of this partial. So you can just fit into that part of any edit form. Every and any edit form can get that partial. Once again, consistency. We looked at edits already. We have index, delete and that's it. Those are all the partials that I have. Those are all the modes that I made. And frankly, the user interface looks the same way. A user would never know that we actually did all of this in the background. Everything is rendering and working as expected. There are buttons on the details page and our delete works as we know, it ought to. All right. I just noticed on the cars details page that okay. So some DTAs or not coming back. So let's fix that while we're here. That is why we're here after. All right, so let's jump back over to our card detail, school behind and I think that has to do with the fact that we're not including enough data on our query here. I'm just going to jump over to index and borrow the code that does the include. Instead of freewriting it from scratch. And I'm just going to place it here. And there we go. So we're doing our cars, include everything and then get the first or default by ID. And save that. Go back and refresh and know the details are showing a good thing. We just clicking through and looking at buttons. And well, that one appeared, right? So if we go to any page, we're going to see the same kind of dynamic. The buttons are there, all of them the same way. And that took, I didn't clean this one up. No problem. That's why we're here. So let me jump over to colors. Takeoff the date created. Alright. I think that's it for this activity. Actually, you can probably try if you're interested for the create buttons because you see they create buttons here, don't look quite like we would want them to look there it is on the cars. I didn't do the create buttons for the other ones. So if it is that you buy into the whole partial buttons and having everything reusable, feel free to try that one on your own. All right guys, so nowhere at the end of another milestone, we've put in some additional tables. And it's turning out to be a wonderful application. We've looked at more JavaScript and jQuery. We looked at how to make some advanced cause hotel it. This server side and client side talk to each other while the application is running on that manifested itself in the form of the cascading drop-down list. We looked at how we can share templating across multiple pages using partials. There's a lot more to do and there's a lot more to learn. But baby steps and practice is what we'll get to it in green. So at this point what we're going to be doing into our GitHub repository, Oliver changes all of our migrations and entities and all the changes we've made with the database or scripts. Everything is not going to get added to our repository. We just put in a nice message that at least gives us synopsis of what the changes are. And then we go commit all and sink. When that is completed, we can proceed to the next module. 25. Setup Data Access Repositories: All right guys, welcome back. So now we want to kind of assess where we are in the project. We set up some features to put in, that's fine. But right now we do need to make sure that we are going to be putting in some foundational concepts so that when we extend our application, we don't do as much harm as we have the potential to do if we don't get the foundation right. I want to focus right now on our use of the B2B is contexts directly in our pages? No, yes, it works. And it was designed by Microsoft, by the Entity Framework Core team to allow for direct injection of the context into the page. And that would be in what we call sculpt monitor, meaning for the lifetime of a request, for the whole lifetime of this code running on get your getting unique context instance. All right, so every time it hits this page, you get a new instance and it can do its work and then it disappears. Automatic artists, it opens a connection, does the work and close connection. Remember that database costs are expensive, so they wanted to make sure that you are as efficient over a database called as possible. And yes, they have done a wonderful job of it. The thing though, is that at times you'd realize that you start repeating queries. So for instance, when we have to do these, drop it on this one, we have to get mixed models and cars colors rather. If we have to get mics on more than one page is rough to repeat this line of code. So yes, repetition will happen. But once again, what is your risk tolerance or own this repetition? Because we have to get this select list inside of the, it for the cars. We also have to do it for a car models. And we're getting the models, whether we're creating our editing, we do have to go and me that same query call. Something might change. What if we had mix? We had some of them that we're not too active or some criteria in our own, which ones we want. Then you might run the risk of having to maintain. If something changes with the way that you get the mix from the database, you're going to have to meet more than one key inches in more than one pleases. And if you forget one of these things, then you might run the risk of not to maintain into application as easily as he could've been maintained. There are a number of things it was I'm getting that really is the reason people build what they call a rapper or a repository around the database operations that you can have 1 of reference for general operations. And you can have specific ones per table. But then it's still 1 of maintenance, 1 of contact. So it's easier to maintain in the long run. So to get this activity started, to set up repository is what we're going to do in our solution is add another file on other projects or other, and it's going to be a class library. I have mine on my recent templates where you can always search templates and we want a C-Sharp class library. You click that click Next, and then we're going to be calling it carbo King up dot repositories. Then I hit Next and we want it to be, we can leave it as a.net five, that's fine. And create. Once we have this new project, we can start dissecting it by setting up some new folders. I just deleted the default file that came with it. And the first folder is going to be contracts. And the other one would be Repository. Pause the Tories. Technically speaking, what we want to do here is follow the concept of interface segregation. That's the I in solid. I keep on talking about solid. It's an acronym with old telling you all of the letters I've been breaking them don't. And each time we're implementing one of them, I do point you towards right. So we've looked at separation of concerns, which is the S. We've looked at dependency injection, which is the D, nowhere looking at the eye, which is interface segregation. So that's why we have contracts and we have repositories. The concept vendor contract is that you are, you are signing a contract to do some work. You haven't done the work yet. However, the contract is that declaration that you are going to be doing the work and this is what you are going to be doing. At that point, we're going to call those interfaces because the interface has the declarations of what is possible, that will be the wording in the contract. Then the actual repository, or what we'll call the implementation, will inherit from. The contract or the interface and be the actual work. So you would have signed the contract. The contract is a dictation of what you're going to do. But then later on you are doing it and you're doing it by the guidance of the contract. So that's kind of the hope that analogy made sense to you, but you will see you exactly what I mean as this comes to fruition. Let us first start off with creating an interface in this Contracts folder. And then we're going to call, it's going to be what I'm using class here, but we're really just going to call it I generic repositories. So naming convention wise, anytime you have an interface, you generally put on a capital I and then whatever it's going to be called, Seeing AI a generic repository. And this is going to be a public interface, not class public interface. This generic repository is going to have the base functions that every database table wherever carry out. We've seen that we can add, remove, remove, edit, and update, basically using or repository or using the database context. So those are the same operations that we should allow our generic repository eukaryote, except we're going to be writing the code one time I went to the resort accounting generic is that we're writing it so that it can happen against any table that is passed in. So now we're going into what we'll call generics in C-sharp. To make something generic, what you do is you use that type brackets. So that's the angle brackets or the greater than and distancing. And then inside of those brackets you're going to give it some token. So I'm just calling it up, please follow. So this would be your generic Tolkien. Generally speak using people used like t or t model or T entity, alcohol, the T entities. So the TI it just means it's a generic. What is generic? What is the generic type I'm expecting it's something of type entity. Then I'll see a where t entity I've been saying give me the generic repository and it's relative to some generic called the entity. And then I went to specify where T entity is. I could say class, I could say int, whatever datatype I specify here. It's basically saying that this is generic as far as it matches this datatype I'm looking for. If I say class, that means equity literally pass any class in which is not necessarily what I want to do. Instead of saying class, I'll see base domain object. Or it's, remember just by trucking. Remember that we have the base entity rather. Sorry, I said object. It should be based on an entity. There we go. Let me an entity. Every single entity that is in our database must at least be the beast domain entity. That way. We ensure that we are always going to be getting something that is actually a database entity. I don't want any other class unless it's a database entities. So that's what I'm specifying here. Red lines because I don't have any reference to this project. So remember when we're sitting up with Bridget, where to add a reference to the data project? Well, there are institutional repositories which is going to have a dependency on the data project. So I need to add that reference. I can just add reference and it will add the using statement for me and everything. And then that red line goes away. All right, looking good. Next up, we want to have the methods that we know we're going to need. Once again, this is the interface or just the contract. So this is just a declaration of what is possible. It's not the actual code. The first one we're going to have is we're just going to be using up my async terminologies. So it's a task that will be returning a list. I went to call it this one, get all. We want to get everything in the database we see, get all. No problem. I don't think I need to do anything else with this one. Let's just leave it at that if we need to extend it later on and weekend did at all, sorry, this should be returning a list of type T entity. So whatever, whatever it is, we passed it as a base domain object into T entity, then this method will dynamically return whatever that T NTT is getting all. Then the next basic one will be to get, one, will want one record went to say int id. So we want to get to one record by ID. And then I'll just go ahead and fill out the rest of them so you can pause, replicate that. But ultimately we just want add another task with returning a Boolean to say the record exists and we pass in the ID. We want something to insert T entity, something to delete when it gets the ID. And I don't know, I don't want to update when he gets D entity. Those are the general methods that we expect to carry out against every single table. Once again, this is the generic. Next step. We need to set up a class that's going to implement this generic behavior. Inside of the repositories folder. I'm going to add a new class this time, and it's going to be called generic repository. So go ahead and add that. And then this one public class generic repository. And it has to be generic also. So it's relative to In NTT. It puts it in art that brackets entity and it inherits from generic repository. All right, so remember that once again we have the contract and then we have the implementation. We signed off that this is the work we're going to be doing. No work starts. This is the inheritance where we're seeing, okay. Whatever it is that the contract said would need to do. I need to go ahead and do it. The inheritance I generic repository. And then we just go ahead and control dot at the usings. We're going to have to of course specify that this is generic to t entity where t and t is of type BCE domain is don't mean entity. Similar to what we just did except just a little more nuance law because they are seen to colon's one is the initial inheritance and delta one is just the same decoration that we have to do just to make sure everybody knows that. Basically mean entity is what the entity should represent. So the reason we can use base, let me an entity once again is that it is being used by all the entities. So technically, while each entities its own datatype at their base, they're really the same datatype in the form of bees domain entities. So this is like a unique identifier for anything that is an entity here, add a new class tomorrow that's an entity. Just make it the inherited from b assuming entity, and automatically they all share the same identity. Now this red line here is going to be because it's saying I need to implement. So once you have an interface that has methods in there, you need to implement. So you sign the contract and all you need to start doing the work. I just have to do Control dots. And it says implement interface, press Enter and look at that. It just generated each method stub relative to the declarations and made here. If I make any change instead of the contract, then I need to make sure that I meet the relative change here in the implementation. Before we start with our implementations, what we need to do is inject. So if I need a connection to the database, I need to do something similar to what we had been doing in our pages where we the door injection of our context and all of that was generated for us. I explained what it was doing, but it was generated for us this time. There's no generic left and right to told ourselves. So let's get started on that null. To start, you can just write a CT OR press Tab twice. You get your way, you call the constructor. Then I need to inject in a copy of my car booking up DB context. I'm just going to say car booking up DB context. And this is inside of the parameter off the constructor. I'm just going to call it context. All right, we're used to the word context. I won't change the name here. Then I just do Control duct. And I can see creates an assign field contexts though when I do that, you see it looks the same way it looked on in our pages. Private readable indeed, it's just you can take off the excess, whatever it is. Agree, if you're using the steam of Visual Studio and needs agree, let that means it's actually optional because you have the namespace already. That's all that's really happening there, but it's the same thing, carbocation, a context, context and then it initializes it. Now notice it uses an underscore here, but he didn't give us an underscore in overall. And so personally, I prefer to use the underscore because I like to see the fields different from the other regular variables or properties through that on the score, I tend to use underscores. I'll replace it here. Control dot. And let's do the Visual Studio refactor to anywhere else equals being used. That's the only reason you will see the underscore and Nazis on the square of those a month to you. You don't have to do that's my personal conviction really. Let us look at another line where we have to initialize the DB sit. So private, read-only. So read-only fields, as disruptive as the name is, a read-only field means that once you set something as we don't lead can only be set inside of the constructor and nowhere else. Once this file is called, discuss is called, the constructor is called. These read-only fields will be initialized and then they cannot be changed afterwards. So if you write code, inadvertently change it, it would just give you an error during runtime that T are trying to do something that's illegal. The compiler might not tell you, but the application will definitely crash because it is not possible. We make a private read-only DB sit relative to t0 entity. So remember D entity represents the entity for the class, for the database rather, and we're just going to call that one dB. So control duct. And I'm adding the using statement for Entity Framework Core problem. And then instead of the constructor, the only place I can set the value, I'm going to initialize this to C. B B is equal to the context dot. And we can call this method called sit. Sit creates a DB set relative to t0 entity, no problem. Set. And T entity. I'm retrieving the base, the connection. So this is the connection to the entire database context. And then dB would be the connection to the specific table relative to whatever table I am requesting an action against. That. That's how everything connects. So let us start implementing these and this won't take too long because we're generally familiar with the code that needs to be carried or tear in the delete. Let's look at the delete operation that we would have implemented in our pages. Remember that we have some delete pages. You could ever move them if you wanted to. But we had done our own delete in the index anyway. And what did it do? Firstly, it phoned it and then it made sure it wasn't null and then it removed it. That's what the delete generally has to do a test to find the record and then it says to remove the record. So it's the same thing in this implementation. Firstly, we'll say var entity is equal to, we can see underscore DB dot. Now db dot means the exact table that I'm in. And you notice that we have all of the methods available to us. So we'll say find and we'll just use a For async where they set this as our task. No problem. So find async by ID. Then we say underscore DB dot, remove the entity. All right, it looks good. So at this point it's complaining because find asynchronous, I'm not a waiting. And in a moment our weights, it's going to start complaining again. Let me put that occurred, please. Variable that weight. And it's going to start completing again because of method isn't async second Disease Control dot and converts it to AC for me. That's one bone and a few to go. Next up is exists. What exists looked like, I think in the edit we had to do something with a exists where it said return contexts dot the table with that condition. No problem. So I'm actually just going to copy this code and we can change it up just to see why it looks slightly different. So yes, we're going to return. We're not returning context dot anything this time. Instead we're returning underscore DB because that represents the exit, the specific table this time, which then means I don't need that car models because I really don't know which table I'm in until it hits this implementation and initializes the BBC made the assumption that it's contexts, not car models, it can be anything. So DB will represent that anything. But then any is still the method I need to use. As a matter of fact, there isn't any async. There we go. And then it looks at the condition. Any acing this needs to wait and then Control dots to meet them afloat async, and everybody's happy. All right, coming together nice and say See how the code looks very similar. But then once again, it's generic because here it is definitely looking for car models. And we might not necessarily know which entity where dealing with at the time. Let us continue with our implementation so we get to do and get relatively simple. All we have to do here is say var entity is equal to o, it find a sink. What I am getting a few errors here. One, because this is a deadly mistake. This should not be returning, at least get all returning the list gets you to only return one that's no problem. Have to meet the change in both the interface and the implementation. So get shouldn't have list there, it should just return task T entity. Alright. Then we can just modify that here. Because if we go up, we see that this seasonal complaining because the two method stops don't look alike when I made that correction, It's no longer complaining. All right, next up, control dot to make the method Async. And then everybody should be happy. But this is saying not all paths return a value. So I could actually just change the sentence, say return. Yeah, there we go. Next, we have something similar for it to get all. So I'm just going to say return. Instead of db.find a sink, it would be db dot to list a sync, once again, asynchronous, but McCoy inclusions, insert and update will have similar code. Insert, we're just saying dB at async and we're adding the entity that will be passed in and seeing so use your oh, wait, I made the method Async and air void. They're not returning anything such as only a task. This one is void. So there are no real update async methods. And that's because of the whole concurrency or potential concurrency thing that we had discussed in the earlier days. Because you don't want to risk to update operations on the same record, on the same thread or on different threads rather. So asynchronous programming will create a different thread. That's why you can have multiple ad operations, multiple retrieval operations on happening simultaneously, but then an update is kinda delete is kind of risky. You'd notice that these two are not necessarily asynchronous movies, not the asynchronous. And there's nothing asynchronous, double the attachment here. Those needs to happen one at a time, ensure consistency. So now we have all our repository, generic repository created. I'm just going to do a build Control Shift and B just to make sure that everything is building properly. There we go. No, I'm not going to go any further. I think those are lots of inflammation to soak up. So you can just review all of it and see how all of these dots connect to each other and how everything is tied in. The last thing I'm going to do, however, is add a reference for our new project to our carb looking up project. That's going to have me rearranging the dependencies because I'm going to add a project or a friend's tool, repositories one. Okay? And then the thing is that repositories has referenced to the data projects. So if I remove the data reference and then do a build, then we see that it will still successful. So at this point, we don't need a direct reference from our web application to our entity project because it's talking to the repositories. The repositories will have that director reference tool, that data. And then the data project has the third-party references to Entity Framework, Core and such and so forth. So the hierarchy is still intact. If you look, you'll see that none of our quota is really broken. But ultimately what we want to do is not have this DB context directly injected into our pages. When we come back, we're going to be reflecting our code such that it will one nor a boat and register the repository that we have created. And then we will swap out the code to use the repository. And then for more complex operations that those that require includes on some of the fields and so on. We'll look at whole. We need to modify our repository on our code to facilitate those specialized situations. 26. Add First Repository Code : Guys, welcome back. So what we've just accomplished was setting up a little wrapper around overhaul database context and removing some of the direct references before between our web application and the database. So we've put in this middle ear, which some people would describe as the business logic layer. Because if we have anything special to do, any special operations, wouldn't want to write the code unnecessarily in the web application. We just wanted to call a method and then let that method meet the decisions and do anything that needs to be done that is of a fancy nature for lack of a bit of expression. So that would be what our repository layer really represents. Know, this Lear can grow. We've only kind of obstructed a lot of the operations into two files right now. But there is potential for growth and you will see that it will need to extend based on some of the operations we have to carry out in order to make the repositories available for dependency injection into our web application. Like what we are able to do with the DB context. What we need to do is jump forwards or startup and register them as a sculpt services. So in the configure services, remember that we had modified it to add the DB context that has to stay. But what we can do is say services. And we can see add scoped in parentheses. I'm going to say type of generic repository with empty brackets. Then I'm letting it know that where you see the interface, it is implemented by the generic repository and also with the tight brackets. So you might see similar code written at different way where you actually say add scoped, open bracket type and its implementation. But because we're using generics, this is how it has to be done. And it's just another way. It's basically the same kind of code. Later on when we have specific repositories and you'll see the other style of writing this line. But for now, we just add scoped. So there are actually a few kinds of injection models. Injection models meaning hole services are injected in their lifetime thrill to what we call our request or throat, the runtime of the application. For context, we have add scoped. So we had to add scoped at school. It means that for your carrying out an operation until you finish that operation, you will use one instance of this, whatever it is that we're giving us. In this case, you use one instance of the generic repository for as long as you're carrying out an operation or a set of operations on one page. Transient means that each operation that you're going to start with always give you new one. So add transient is fine if you are doing that with escort service. Because the DB context is scoped and the generic repository relies on scoped, we could easily meet the repository either transient or sculpt. No problem. The other one is singleton. Singleton, which means that I'm going to be one instance for the entire application. There are times when you'd want that maybe like with a config file, something that's never changed. He never expected to be dynamic. You make it a single time. You don't have to change that every single time something happens or every time the PhD and GCF to get a new instance of it. That's more for our database operations and certain other kinds of services like an email service, you'd definitely want that to be transient because if multiple emails needs to be sent out one time, you want multiple objects or incense, he's off that. And they should close as soon as they're finished. You can mix and match. You don't necessarily have to remember all of them and just figure out which one all the time I'm black. But certain principles can be used to figure out which one is best for what kind of service. And this database services definitely best as Sculpt. If you wanted a clue, if you hover over the add DB context, you'd actually see it tells you that it's scoped by default. Anything that is dependent on database context, just make it sculpt I, you should be fine. Now that we have included our generic repository, let's look at how it works. So I'm going to jump over to one that's very simple. Let's start with mics. Me in our Create Page four mix, what I'm going to do is instead of injecting the DB context directly in, I'm going to change the salt, so I'm just going to remove the DB context from the injection. And I'm going to say give me a generic repository of to include missing references. And I can see relative tool. I know I'm in mix, so relative to the middle class. Then I can call it that. I just thought it repository and then Control dots. Let it initialize an created a field. Then I can remove the references to the context and repository on the score repository, they just renamed that. No, it's renamed nowhere using repository instead of the context. And as expected, we have a few arrows appearing fine. No, this was a create operation. So that means instead of seeing context dot mix dot add me, I can know see repository dot insert. And then it was asynchronous after our weight. This is very important that we did not implement a Save Changes in our repository. So remember that every time we augmented data we have to call save changes. If we jump over and I can just do Control F12 to jump over to the implementation of the method. Notice that there are no save changes happening anywhere, right? So we are updating where inserting, we're deleting our not saving. So we lift that onenote. No problem. That's why it's good to catch these things from. No. I'm just going to go ahead and I'm going to make this one a task that returns an int. And it's going to be save changes. And that made it into because if changes by default usually returns an integer anyways, so I'm just representing that. Well, this is like our upper function. So if I jump over to the implementation, it will complain, Hey, Union Avenue method, please implement control dot enter. It's no implemented. And then all we really have to do is return context. So we have underscored contexts. Thought Save Changes is sink. It's async, so I have to wait, of course, Control dots MC method Async and remove the excess space. There we go. No, we can see if GnG is no problem. What we can do is instead of calling the Save changes every single time that I call, we do the insert here and then we have to call the Save Changes in a separate line. We know that these methods needs to save changes. It's easy enough for me to just see after the insert, after, if you add, then go ahead and call your local Save Changes method. That's our weight. This will reduce the number of times I, you'll see the Save changes all over the application because we know wants to do an insert, tinges needs to be saved through everything here. No problem. And then everything would be running on the same context. So no matter how many operations you do using the WAN repository instance, it will always save changes at the end of the d. So let's just wait, see if g and g, So the insert, and it's always save changes with the update. And then look at this, uh, we'd save changes with the update, um, because it is not asynchronous, so no problem we can reflect as we go along. And the delete also is not asynchronous, but this one was asynchronous because it did something asynchronous. So now we can bring the update up from being void Control dots. We can make the method Async. But instead of doing that, what I went to do is modify the interface and make it a task. Just let delete is a task, then that would make it more consistent. So we can just see async task Update. And then everybody's happy knowing our creates. We don't need this line because once we do the insert, we know the insertion and the saving of changes will happen. That's all in one line. If we need to make a change to a whole inserts are made. We have 1 of reference. If there were multiple places in the application, you have to do this kind of operation. And he wanted everywhere to be consistent. Instead of making code changes in all the places, we have 1 control of 121 of reference to me, those changes. Someone to show you something though. What if For every time that I needed to save the change, remember that we had added deed created and let me let me go back to the beast. I mean, entity we had said deed created. Remember that? No. No. No. We haven't made any modifications to facilitate the creative as I myself have been removing it from the interface because they saw it as a hindrance. Because really and truly the users should not be able to see it or interact with it. It's really for our internal system. However, I want to make sure that every time I record these being created, disvalue, is it all right? Going back to what I said, instead of doing it in multiple places and for everything I can meet. Everything happened instead of NIH repository. So it gives me a bit more control over the operations. That being said, let's modify our Save Changes method to add more data, manipulate the data or whatever it is we want to do before. It's actually goes to the database context and saves. Here, we can get the entries that are a boat to be saved from the context by saying just to afford it. So I don't know how many things are going to be saved that this point because we could have done multiple operations, whatever it is. So I'm just going to save for each entry in the context dot. And then there's this thing called change trucker. So this is actually so Entity Framework is actually trucking that when they gave you an entity, It's actually seeing did you modify this entity? Did anything about this entity change? That's why wouldn't we do the update? We are seeing attach and then change the states to modify it so that Entity Framework knows that this was modified. So when you see if changes here beating, it will automatically know what kind of statement to generate based on the state of the entity. So T instructor is what is being used as that that register to see this one change. This one didn't this one did this one didn't change. Instructor is I can say get me the entries and then this is a collection so I can use brackets no, to parse them out into something specific. So when I say something specific, I can say give me all the entries. That's our car. Get me all the entries of car model, but I don't know what is being saved. This is generic. So instead I'm going to say anything that is being saved that is of type base domain entity, which could be any one of our entities that we have. You see, just using that little bit of inheritance is allowing us to do wonderful generic things, right? One bit of code to serve many tables and just be flexible. I'm saying get me each entry that is in the chain structure that is often best to me an entity. And then I can extend this to say that we're we're sitting up date created. I only want the ones that have the entity state as modified contexts entry states. I can see it That's where Q lambda expression Q dot state is equivalent to. And then entities state that is given to us by Entity Framework Core. And here are all the potential states unchanged, added, the touch modified, deleted. All right, so I want that when it is being added, I want all the entries that when they're being added, I can see entry dot Entity. Entity here is wonderful. The generic and bodies based on this domain entity. Dot it created is equal to time dot. So everything is coming together. Then once I do that, it allows me to not need to sit down and we're both sitting that date created on every single record or every single time. Something is able to be creative enough to go to every create Bij code to see before you send it over McDonald created is equal to d time no, and descenders, and I've just doing it one place. Once something is created, this will happen. Then it will save changes. And you can extend this to the one on both things because we could have had a date modified. So you could easily say, Get me where the state is added or modified. If the state is added, the new set, this if it is modify it you said didn't modified, etcetera still fly. So I'm just showing you that this is wonderfully flexible. So at this point I'm just going to do a quick build and we're going to jump in and test our mix and see the difference, right? No, The only changes we've made is to create Pj. That's fine. So Create New. And I'm going to say test new repository. This is not me. But let's just go ahead and hit Create art. So there are still works. Let us look in the database and see what came by the gods sit for the date period. And so drilling down to the database and already to be clubbed carbocation up. In our mix table, the most recent record should have the deet and there we go. Every other one had the default date, this one issue in the cart data, the exact timestamp of when it was created. That's how easy that was to know if we change all the create quote and I'm going to challenge you to do that the same way that we modified the Create model here. For me, I'm going to challenge you to go and do the same for colors, do the same for car models. It should be easy enough to do the same for cars. Yeah, because the CTO straightforward enough. Dude that support all of the creates and if you feel up to it, go ahead and do the same thing for the edit. Because it's pretty much the same thing wherever you had contexts that safety hinges on context, love doing stuff. Here's that same attach with the entities state modified Cmd, G, and G. That's all we did in our update method. Wherever you have those, try and swap them out for the repository code. So I'm going to do it and when we come back we can compare what was done. 27. Refactoring Pages : Welcome back guys. So when we were here last time, we had an assignment where we should complete other pages. I hope you attempted it on your own. And if you run into issues along the way, which wouldn't be surprising, don't feel as though you are not doing the job correctly or so on. There are certain parts of it that will need a bit more explanation than some. But ultimately, I hope you attempted it and I hope you understand what we are trying to accomplish here. What I'm going to do is review what we did the last time. And then we're going to walk through each of the general changes. And there are some changes that require a bit more code to be written. So let's do those together. Let's start off with reviewing what we did last time we're dealing with mics and we have modified the Create page, right? So we did the injection of the repository onto our Create Page relative to me, that's a generic repository relative to mic. Then we could replace all of that fancy code of getting it and story and density changes with one line of code. Just the insert. Let's move on. So I set up my delete page. We know we don't need to delete bits. I'm actually just going to delete the delete page right there. And then let's look at details together. So details we do the same thing, we do our injection. So we replace the context injection with the generic repository injection. And then where we would have been doing the first or default get that. We just replaced that with our weights repository dot get ID dot volume. If I'm moving along too quickly or you haven't done it yet, feel free to pause and replicate as I go along, but please make sure that you're internalizing the explanations of the code as I go along. Let us look at the edit. Same injection. I'm sure you start realizing our common theme across the mall. No, All we have to do is inject our repository relative to what entity where a boat to use on the page. Then for the on get this line basically him we as the details get the same line. I didn't change any of the default quarter on the checks. All of those are still necessary. I'm just replacing the code regarding the context then in the post, instead of changing the state to modify it and then saving changes, I just put the updating there. Because on update, it is going to go ahead and see if g and g is anyway. So we don't have to worry about anything wrong with that. All we do is change that to update inside a try catch and everything should operate the same way. Another slash manage change would have been with the exists. Exists was not asynchronous, it was just private bool make exists and it gets the ID. So I changed it to say, I'll wait, repository that exists with the ID that made the myth loader the asynchronous. So by using the control dot, it automatically appended async to the name of the method. No problem made it async, no problem. Then one other thing you'd have to do is make sure that you call a weight in that method. Call at the top here. The names and everything would be able to, you want to use the IntelliSense, but you just have to make sure that you put in that line. Those changes pretty much the same changes for the same pages, for colors because those two pages or these two entities have no dependencies. Colors, same thing except we're injecting our repository ready to have to color. And then we use the same line there for a lateral need the delete. So I'm going to remove that for the details. We have the same thing. Where we just get the details of the color for the edit, we have the same injection where we get the color. And then later on we update the color when necessary. The index. I skipped over the index for the mic, also also index for both Mecca and color. Pretty simple. Participate or we inject or repositories. List will be get all. No problem. I think this should be mixed. I might have reading that. If not, then you can go ahead. I made that change. So that's makes you will get all and then ON delete, all we have to do is call the delete. If Record ID is equal to know we go to not phone. Otherwise we just call the delete passing in the record ID. That's all there is to it. Nice and simple and consistent. So see, I didn't mean that she is hearing the colors. No problem. Let's do that together once again. And literally I'm just going to copy this line because it's basically the same code. And I can replace all of this with that one line of code. Because everybody's being called repository and you can get specific if you want. I'm not saying you have to call it repository and everybody needs to have it called a repository. You might want to get specific and call this one Color repository, make repository, etc. No problem. But at the end of the day, the base code and the way it looks, the structure is always going to be consistent. We've done that for colors. We've done that for me, makes no problem. Let's look at car models. And also a car models is a bit more complicated in that we have to load initial data. So you see I did some of the changes and I left some unknown. Just think he is this is where you were. And if not, then feel free once again too, pause and replicate what you see on my screen. We have replaced the insert code in the post method already. It's repository insert car model, fine, but then we need to get the list of mix, which means I need a repository that can get me the mix. Although under repository prisons is relative to car model not mix. This is where you'd probably want to get specific with the name of the repository. So in this case, I would want to call this car model repository and I'll just rename, and I'll just copy, paste three, use this name and rename accordingly sono. Everybody knows that this is car model repository. So car model repository insert that. I need a repository that's relative to mix. No problem. I can easily go here. I'm just going to copy this bit, which you say I generic repository relative to me. And I went to call this one mix repository. This is where naming it specifically comes into play and then Control dots let it create an assigned a field. And injection happens. Of course we use our underscore. And after doing all of that, no, I can just jump down here and see me x is equal to a new select list. Await the mix repository dot get to all. Look at that. Everybody's happy. That's it. So you can have more than one repositories in the same page. So I have a repository that talks to the car model table. And I've repository talking to make I guess what They're both the same code base. That is really all I needed to do for the create. So I have to repeat that feat for the editor. Of course we know what we do is create two basically after replicate with edit. I'm just going to copy and paste as almost never ******. I went to do this even quicker. I'm just going to take all of this, popped up and replace all of that in the Edit, and then just rename the constructor field or constructor name. My repository, what was repositories? No car model repository. And then car motor repository again. And then this would be our weight mixed repository. Dot get all. Factoring can be tedious, but there are ways to speed it up when you copy NPS, similar quota, you know exactly what to change it. Let's look at it. I took a few seconds to get edit and create up to scratch. I'm going to remove the delete page for me. I don't need it for the details. Already changed all the details because all we need is a car model. But then there's something else you may need to look at, which is the fat that car model has mix. So we would need to include the mix details in the car model tables. I don't think we had done it before. I switched over to the repository. But that is something that we're definitely going to have to implement in order for the details page to show the mic properly. So we never modified the interface, so we never had to modify the data coming back. Really and truly, this should be CAR model dot dot name because we wanted to see, and this is the car model and this is the mic. It's related to that point. We definitely need to modify how we get the data because our Getty's just getting the data. But we already saw that when we want to get with the details of related records, we have to do an includes and so on. And we don't know what to include the generic because I can't eat just include something on the table because different tables have different properties that are included. So we're definitely went after at some custom code for a car model in that scenario. And then by extension, we're going to have to extend it for the index also because when we get the all the index page, we probably wanted to not only display the name, just like with the details, you probably wanted to display the mic also. I mean, that's up to you. This one is probably optional. I'm not going to extend the index to show the mic, but we will have to do that for our cars. So I haven't finished watching all the cars is, and you can see here I've got some of them are datatypes wrong. Did some refactoring, some global refactoring that mixed up a number of things. But when you look at this, you see I'm getting a car repository. Haven't changed much over the code here. But then we have the same issue where we need the mix, the colors, the models which was suspiciously missing. We do need to bring those in. So that means I would need a re-perform mix or read before models and our repo for colors. Yes, we got rid of one SEO by taking all the contexts because conceptually the contexts should never directly interact with the controller or the page. But then we created a model where we created such a delineation between the three data types that we have to inject three different instances of the repository. As always see, there are times when you do something because it makes sense, but then it matters how granular you need to get based on your objectives. Not withstanding that. Let's just go ahead and get those additional repositories. I didn't want to bore you if you watching me do it, but this is basically what it looks like and I'm just going to breed the lines. You can see where each line starts and stops. Just say it's very, very clear. We just go ahead and inject repository per type that we need. We go ahead and initialize those fields. No, relative to each call, we are going to make use of the cart repository it. So here I'll say underscore the pirate. So this is the car repository. This is the Create, so it's inserts and we're passing in the car. Alright, any analytics that intelligence will always guide you as to watch datatype need is needed based on the repository or eaten. There we go ahead and insert our car. Don't hear. We're doing on car models. So we know that this is a cascading drop-down list area. So at this point would definitely need some custom code. Because when we get r gets all, we are getting all records one time, but then we are getting based on ID. We get one required based on the primary key ID here. We're doing neither were getting all car models were a completely different row is equal to a different values. So we definitely need to have some custom code for that, but we're not quite there yet. Lets us make sure that all of our common methods the same. So for the mix, so I went to see on a score mixer repository dot get all. Then I can just replace each of these. I'll just copy and paste an industry name, this car models. I'm one of those repository and this was Colors. Colors. Colors. Do we have color? Color? Let me just copy and paste into the senseless. It's a slow there. All right, so at least these are fixed. Now I'm going to pause right there. And if you look at the details page and look at the index page, and like I said, for the edit page and even the Create where we have the cascading drop-down lists, we have to make sure that we are looking for the card things at the current time. So when we come back, we will look at how we can extend our repositories. 28. Complete Repositories: All right guys, so we're buck and what we'll be doing in this lesson is sitting up some custom repositories. Let me talk about customer repositories. There are times when for certain entities or a certain operations, we need to have custom code that cannot be generic. So case in point would be for our create where we have our cascading drop-down list. We definitely need some custom methods here to facilitate hardware looking at the car models in this particular situation. So that means I'm going to have to extend or models or car models to have its own repository with its own custom methods. Another example of why this might be needed would be like when we want to look at the details or even the list of the cars, we have to include these specific details for the car when looking on the details model. And when we're reading about the list on the index, we definitely need the Includes also. Those are reasons to kind of extend your code. This is no, this isn't really an official term in programming, but I call it pain Driven Development. Anybody or other developers with it. In Driven Development, which means you do what is necessary for the goal at hand. And you get fancy when he sees required, but you don't just start off funds it because you might overdo something that's very simple. So at this point we see the need for this refactor. So let us go ahead and do it. The first thing we're going to do is go back to our repositories project. I went to right-click contracts and then I'm going to add a new item and item in the form of an interface. This one I'm going to call it car models repository. We know what we need to make it public interface I car models repository. So now what does this contract? What is the work that this contract needs to implement? Well, I went to say you need to implement a method that is a task that's returns a list of car models, someone to call it get car models by meek, and it takes a parameter int make ID. Now with that, that contract in place, I need an implementation which I'm going to call a car models repository. And that one will be created in the repositories folder. And I just realize I misspelled repositories at this point. I am so sorry about that. Repositories that knows who loves some ramifications underneath is being used, but that's fine. We can create those easily. So go ahead and create that new file. I'll just go ahead and fix the, fix this spelling error as it were. So know when you have your implementation class, well, we need to do is inherit from AI, a car models repository. So that's easy enough, but this is going to have to be a WE inheritance because for one, this models repository should be able to carry out everything that the generic can-do. It should be able to do everything to generic can do, as well as anything customized. Our new contract is reserved for customized operations relative to the car model. But then it still needs to be able to carry out everything that the generic can do, which is save changes and this and that and that. What we need to do when we have our implementation is inherit from generic repository it relative to car model. All right, So we're seeing the implementation of the repository for our car model. I want to inherit from that, include any missing references, as well as my costume contract. So when you look at this now, and I do Control dot implement interface, it will only implement the work prescribed by this contract. However, they work in applied by the generic repository is also there in the background. Oh, it's complaining to me that there is no argument given that it's corresponds with if I'm inheriting from something that has an injection generic repository, it has an injection for the context. If I call on car models repository, which is inheriting from that, then car models repository needs to provide all that the base class needs. So long story short, and it wasn't constructor that is going to take the CMDB contexts or just even copy it. Car booking DB context, go ahead and insert any missing references, but also creates an assigned the field. Then I'm going to have to provide the best method. With an instance of the context, it's almost like a daisy chain is like a handoff. So Albert calling the contract for i car model, it will know its implementation is this. When that is called, it goes, it fetches the context from the IOC container and says, Okay, base, which is our generic Repository. Here's a copy of the context that I have. So they're both on the same contexts thread, right? No. And then I also have the implementation of the cost of methods for the repository. At this point, get car models by mic. I'm not even going to do much hard work. I'm just going to jump back over to the create tours it in cars. We have the create method which has all of these. I'm just going to copy all of this. Go back over to my car models repository. I'm going to paste all of that. So VAR models will be equal to our weights, the contexts or renaming. Let's rename that on the square contexts. So I wait the context dot car models where all of that, and then I'll just return models. I'm getting this error because it's not the async, make the method Async. And there we go, Everything is no good. So now we have a customer repository that can give us the customized functionality for this customized SQL query. That point in the create another split and see if everything, all the changes that we make him always pressing Control S in this repository. I don't need to have the generic repository for a car model because this is going to be used more than once. This car model yes, car model repository is being used to get our needs to be used to get the entire list of car models as well as get them relative to make ID. I can actually replace the eye generic with AI car models repository. This one is not the generic, this one I need the costal method, getting it by the meek. And then I can just no red line because it's still has access to okay. I'm getting a red line and I think that's because I failed to inherits. I apologize, I should have inherited from the generic repository at this point relative to car model. All right, so the same way that the interface was inheriting or the implementation inherited from the generic. The interfacing is inherited from the eye generic, so that it can see all of the work that the generic can do as well as give you its own work. And then let me just zoom back over to the implementation. There are no errors here because I'm already making reference to the implementation, which basically the idea is interpreting that's where the work for it to get tall and all the other ones for the generic R, as well as the custom methods as defined by the custom contract, will be implemented here. When I jump back over to the Create. No, The red line is gone. There we go. All right, so for this part of it, I can actually just return new weight. My car repository dot get car models by Meek, giving it the Meek ID that came in as a parameter. Which eliminates all of this code. I don't need that code. You'll see once again, if that code changes, I just have one place to change it or it just looks to me, this looks much cleaner than having the, all the context code written note instead of the page. This looks so much cleaner. Once again, if it works, it's good. It's just a matter of what are your objectives and do you need and maintainable to a point or what are the problems that you're trying to solve? Don't just do this because you know the pattern and I need to hold to do it, do it because it is solving a problem that you have. That is our adjustment to the car models. To create BH rather, notice I a generic car models because we have this new repository that is custom and it needs to be injected in. I need to let the application that we have another one that can be injected in. I did sculpt for the generic, getting an error here because that changes namespace, no problem. But then I also need to add scoped for the new customer is born, right? So I went to say Add school type bracket, car model, car models repository, coma. And the implementation of this will be car models repository. That's the difference in terms of dimensions. So because this one is generic, who get after at a different, but generally speaking, that's how you will see the interface or contract and implementation peering goal when they're being registered in the IOC container. Alright, so that's really what we have to do to make sure that it works. Let's go back to the details part of car. Well, the details parts of car models have a similar story where anywhere we have the generic car model, we could actually just use our specific class that we just defined I car models repository. Instead of the generic. This is what we're using anytime we're dealing with car models because custom methods like getting the car model with the details is no necessary. In this repository. What I'm going to do is jump back over to our contract. And I'm going to create another method That's going to say return just the car model. And I went to see get car model with details. Then we have to give you the idea of the car model that we want to retrieve with details. Now once I've done this and put these little tabs here so I can navigate easily to file. So if you don't have those tubs I just showed you, you can go to Tools, Options, go to C takes editor, then C-sharp than advanced and throat all the way down to bottom. And it says show inheritance March, and it's experimental. So I have seen it work for some people and not for some people. That's just so you can enable that. So it makes navigation between parent and child classes as far as inheritance goes much, much easier. Alright, so now there's a new method to be implemented. I'm just going to control implemented. And then I will see here that if I'm getting it with details, what you need to return is my context. Dot car models, dot find are not find car models that include and I went to include my navigation property for the mic. All right, then at the end of all of that LLC first store defaults. Lambda expression where the ID in the record is equal to the idea I'm looking for. So whenever we would call this, we know are guaranteed to get buck the car models with any includes. If we call it the gets, the regular gets its generic, they're annoying Tod's. That's all we can once again put in specific methods for the specific repository, for a specific reason. Let's jump back over to details now. And I can replace this with get car models with our current model with details. I know when car model comes back, it's definitely going to have the navigation property for the milk type included. For the cards. We have a similar problem. We need custom methods for the car repository to be able to get back those with details. And for the index we need to include the details there. Also. What we are going to do is repeat or feet. We're going to have a custom contract and our custom implementation in our repositories project. So here's what the contract is going to look like. I cars repository once again, inheriting from the generic repository relative to car. Then we have our task. Car could get car with details. And the NOR implementation is going to say cars repository inheriting from generic repository relative to car and the contract. So everything gets injected just like we have been doing up until this point. And then we have the method get car with details, of course I made it async and a weight and the same code that was in the details page, I just cut it and paste it right here. I weighed the context dot cars include all of these details and get the first or default. Buck in our details page, we can start off by no longer injecting the context, but now we can inject a car repository or cars repository. This would be, I can just call this one. Repository is still only one there. No problem. Repository. Include missing references, go ahead and create NSA and the field. I remove all traces of the context and then add the underscore just for my peace of mind where we're getting, I just say repository dot get car with details and give it the id dot value. If I didn't explain it before because it's small, multiple, I have to see id dot value. And of course after that. And like I said, I did some refactoring on Visual Studio change too many things on there at 1. So some of my data types are wrong. But after fixing that and I'm sure he didn't have that problem. You'll see here everything is okay with our details page. And this looks much cleaner. So we have to do something like that for the index. Now, I say something like that for the next because this is multiple, this is a whole list with the details. I need another method here that is actually giving me the list. Off car. Went to say get cars with details. And it will get no parameter. And that should be list. We'll go get the list of cars with details. No problem. Implementation Kohlberg over to here, controlled lot implement interface. And I'm just going to repeat that return statement here. So return context of cars with all the includes dot list. And it needs to be a thing so controlled up make method Async and with a semicolon and that's okay. So in our index page, all of these cannot be Repository and of course I need to update the constructor and the injection. So I'm just going to shortcut it. Just copy a similar one, change the few arrows. And then I can notice a repository dot get cards with details and close that of course after 08. And that's basically it seems missing the mixed up data types and we should be good to go. In other places. We're going to have the on post delete, no problems. So I don't have to find anything. I don't have to check if cars no. Instead, if the record IT IS NOT null, I will see repository. And of course I'll have to await this repository Dot Delete and we give it the record ID dot value. That's it. No code nice and clean that you never really wanted to code behind that while the statements and all the complex operations and so on. You want to abstract that ALT. All this should do is call a method, get door at the mythos, do the hard work. I call the method and waiting for the response. You do all the work and just telling me what the outcome is. I went to this point, build just to make sure that I've made all the changes needed. And I have one arrow because in my startup I have the misspelled namespace, but I do need to make sure that I have. Before I car repository, I'm going to show you what kind of error you'll see if you fail to add the fail to register your service. So it's just going to Control F5 to run without debugging. Getting this other arrow because I had renamed meek to mix. All right, so let me try that again. Control F5. And our application is up looking mix colors and models just to make sure that we're seeing the data. So we see here that's our repositories working. If I click Edit, make a change and then save, we see that the changes saved successfully. So we know that the repositories working in that regard, if we look at the others who see all of them coming back. So if I click on the details for models, you'll see the mic is coming about, the details are coming back. Now if I click on cars, Let's close all of these and let's click on cars. Now look at this you're seeing unable to resolve service type for i cars repository while trying to activate index dot models. So that's just a fancy way. I'll see. You forgot to put the registration in the startup file because we didn't do this. You notice everything worked fine for models. All of them work fine for model. It's the same concept. So because we didn't register ie car, so I'll just say I car repository is implemented by car repository. Include any missing references or sorry, That's cars. Keep on forgetting that. That's cars repository. There we go. I can just do a build and the refresh the page or rewrote it in D in, without debugging and click on the course page. I know it's loading. You see you get that blocks off an error. If you forget to your service registration. And by extension, look at that. We're seeing all of our details. If you go to Edit, we're seeing all the details. If we go to create or a cascading drop-down list with still operate as we expect it to. All right, so those are little changes that you want to make our own doubt vacation. That's the key bit clean. But once again, not because you have a hammer, everything should look like a Neil. Lot of the times we learn a pattern and the nave we're seeing the thing, we've used this button. Some applications are simple enough that you don't have to add that level of abstraction and complexity to it. But at the end of the day we see where it does definitely go. A firewall, it increasing How maintainable the application. He's going to be. 29. Repository Section Conclusion : All right, So if you turn other milestone and we're going to do check-in toward GitHub repository. So let's just do a quick recap of what we went through in this section. Firstly, we had identified that we want to reduce some of the quarter repetition and increase the overall maintainability and testability of our application. So step number one to doing that was to create or repositories. So we created what we call the generic repository that had very, what should I say, no, generic for one but very abstract ways of declaring basic form shown is that every single database elements will need to carry out. By doing that, we were able to use two files to compensate for many database tables. So between the generic repository, under generic repository, we have enough code coverage for almost any of the basic scenarios for every one of our tables in the database. By extension, we're able to either automate certain things that we would have had to do in a customized monitor or doing a number of places. In every time we create an element, were able to automate that regardless of which element is being created or we know how to get it down to the base domain entity, which every element will be. Every entity or other will be. And when it is being added, we can go ahead and modify it all before we actually commit it to the database. So those are very key operations in what we are doing. After we had our generic repositories, we also realized that there were certain operations that needed a custom touch. So instead of touching the generic stuff, we go into head and extended it. So being able to extend a class without modifying the main class, that is the Liskov principle and that is the L in solid. We're looking at dependency injection because nowhere creating objects that can be injected in at-will, we're looking at dry, which is don't repeat yourself. We're looking at interface segregation, which is why we have all these contracts and their implementations. Number of principles that go into the four-year. So what do we want to extend? 104 already implemented repositories and saw without the overlay, modifying it and seeing okay, generic repository, household things specific to something else. We create our specific ones, I a car model repository with only car model related operations that require little customize touch. We have the implementation and we have the cars repository also. I did say from, I think our previous model that it would be nice when we're adding a car to see if the license split exists and if it does, don't add it, I do remember seeing it would be nice to do. We never got around to doing it. Let us just look at how that would look. Once again, anything costume that you need, you'll put it in the relative repository. So in this case, I'm just going to duplicate this. Sorry, That's car model I wanted to in cars. So I'm going to duplicate this method. This is only going to return a Boolean. Boolean is going to see get car is lesson split exists. This will take extreme plate number. I'm just going to say play it number. That is its parameter. Once again, if we have within the interface, we go over to the implementation. And then it's going to complete and we go at Control dots, let it implement the interface. And then I can return context. Please look in the cars table and tell me if there is any. And of course we use our async. Any async q-dot license plate number being equal to the plate number that came over. Though because they're a string, you would probably want to put everything to lower because uppercase is different from lowercase is to lower. Another thing you'd want to do is probably to trim it of any species that might be on the altar. Reaches. With those two done to the what's in the database, you also wanted it to whatever value is possible. Everything will be lowercase and everything will be trimmed of all the whitespaces. And then we will check to see if there is any. So I have to await this dot control. The method Async. Now that is extended, nice and easy. If we wanted to incorporate that check node in our Create and by extension, the edit operation. What I can do is do my own check here to see if I can see on the score repository or car repository dots. Just start typing lessons split until I see it. Which I am not, I'm not seeing anything because this is still the generic. No problem. I'm using my costume. I cars repository and I can replace that everywhere so that the injection works properly. Okay. Everybody's good. Sono way. If I look back, I would see that I have access to the custom methods is less than split exists. And then I would pass in the car dots license plate number that's coming from the form. If it exists. What I wanted to do is make the model state invalid because no license plate is present, it is valid. I want it to be invalid. This is in place so I can say model state, dot add error, model error. And this takes two parameters. It says what is the field you want me to add the error tool and what is the error for the field? You can use a string, but then I'll show you the danger or one of the problems that use the stream like this. That's fine. I want it to be added to this field. And the message should say, license split number exists already. By the time I finish adding the model error and it gets to this statement is going to see that it is not valid because there is an error. I did it. And then it will reload the pH showing the error under the field. You can experiment with that. I'm not really going to test that. That's not the point I'm trying to push. What I was saying about the field is that because of strong typing and if it is a case where we end up changing the name of this field, we would have to remember that we have to update the string. It would not automatically change. So to keep it strong desire to what we do is see name of we pass in the direct name of the variable. So it will just convert it to license plate number and know that that is the field women. This is the error message. No problem. I'm just showing how easy to know to just extend the functionality. It's already injected. All it all I did was change the datatype, which is a onetime operation. As you need to extend it, you just put in other methods and you use them to will. That is all that would've been required to extend this functionality so you can go ahead and test it. Like I said, we have to do that in the Edit also. So let me just do that and make sure we have full coverage. Before those posts. We have to do that. Kiara repository once again is the generic. So I have to say over here, I car repository. All right. Change this. I think I repositories might have their own namespace, but I'll fix that. That's fine. At that point. That is all we really need to do to make sure that our contracts and everything are extendable. So you can go ahead and test that. I'm sorry, I'm just trying to find what I needed to change. What's others. Include its cars repository. Apologies. All right, so IQR is repository and then everything should be fine. It'll using statements needed, all errors are gone and the same kind of validation is happening when we edit. This is how easy it is to add custom validations because of our custom database methods. With us. That's it, I'm done. Let's go with a good changes. Once again get changes should be to the society. If not, you go to view and bring up the window, get changes. You'll put in your commit message. And then you can just commit all and sink. That will push your changes to GitHub, pull down any changes made by your colleagues accordingly. 30. User Authentication Setup : Guys, welcome back. So at this point, we have a lot of functionality working for us. And even though it may not seem that fancy, you have come to the realization or buy know that all applications are doing, are reading from the database, updating data, putting data there, or removing data. That's all that's really there to it. It doesn't matter how complicated it may seem. All funds eat may seem. That is all it comes down to. If you want to extend this application to do more things, putting more tables, I mean, it is called car booking. And us today It's all we're doing is putting in the cars. If you want to be able to put in the actual booking than no problem. Let's look at doing that. However, before I put you in that Beta functionality, I wanted to secure the application to an extent, reason being we don't need one. We need to be able to know who is doing what in our application. At this point, anybody can just run the application and start adding cars, adding me exciting models. We want to restrict certain things to one I registered user who we know. And to later on we looked at how we can sit levels between the different users who are able to do things in our application. We're going to start off by extending our DB context to be able to handle user related operations. That's actually simpler than it sounds. All we have to do is instead of saying DB contexts, we say identity, DB context. Identity is the framework or the library given to us by dotnet core to start adding user related operations to our application. So by seeing identity DB context for the inheritance, I Control dots. You'll see that I need to include some new libraries. We are using NuGet weekend to say install package, find and install buds. Remember that we had some versioning problems with the Entity Framework Core and the version of the library. It's actually safer to just use NuGet manually. So I'm going to right-click go to Manage NuGet packages. And for our installed, we know that we're working with 5.8 right now. So I'm going to go over to bros and I'm going to look for identity. I just say I've been identity, identity core and then we see Microsoft.ASP.net Core identity to Entity Framework Core. So that's the one that we want and then we're dealing with 5, it. This is how you use NuGet package manager to make sure that all of the versions are on the same liver. Then I hit Install, allow it to do its thing, accept any problems that come up. When that is done, I can jump back over to my DB context and include the missing using statement. There we go, and everybody's happy. All right, looking good so far. No. In our it starts off file. We'll see that we have a little error here where we were adding the DB contexts. And it is saying that we need the using statements. So I'm just going to Control dots. And it says install the package reference that data or just added a reference tool. I'm just going to add the reference. Rather I'll just use a local version. So I'll just use local version. And that's another strength of package management. It allows us to make sure that we're not, that all of our versions are on the same level. So know that error has disappeared and always still in the startup. And what we need to do is to let the startup know that we will be using identity services in the application. So I went to say services dot add should see default identity. If not, then at identity, There we go. So you can add identity core. Adding identity core knowledge, they will say which user types, the default user type you get with identities, identity user. And we looked at how this can be extended in a few. But we'll just add with identity user put in the missing using statements, and then we can pass in options if we want. So when I say it can pass in options, I can see options with a lambda expression, options. And we can explore different options that we want to go for our users. And there are cones. For instance, what we're going to do is see options on a sign-in require confirmed a cone to know like when you sign up for our website and they send you the Tolkien to say, please confirm their colon's, what's until the due date. You can't really login. Well, that's what we can enforce here. I can see require confirmed account. By default, it's going to be required. So I'm actually just going to say equals false. Just because it's an internal application, I will probably won't be going through the rigors off asking anybody to confirm their cones anyway. But I'm just showing you what is possible. So you have a bunch of options at your disposal. And if you need to set multiple, you can just do that using an object block. And you terminate each line with a semicolon and you add as many options as you need to. We are adding identity core relative to identity user, which is a default user class given to us by identity framework or identity core other. And then we can say add rules. If we wanted to use rules, we can say I want to use rules on the row class. There's a default one in identity rule. Once again, we can customize that. I don't generally customize that one, to be honest, I usually use a default rule. Then at the end of that we need to tell it Add Entity Framework stores. So I need to tell it where are we storing our user information? So it would just really be asking for our DB context. Which contexts should I use to infer which database I need to store the user related tables in. Now the thing about it is some people like to use the same database for application and user related things. Some people separate them. In this activity, I'm going to keep it simple and I'm going to use the same context for both the regular stuff and the user stuff. Once again, some people separated. So if you wanted to separate it, you would create another DB context. Just like all we have this one here. What do you could do is leave this one as only inheriting from DB contexts and it creates another DB contexts which inherits from identity DB contexts. It wouldn't need any tables because you'll see how justice inheritance will give us the tables that we want. And then you would be fine. And of course you'd have to have the other connection string here. And you set up your DB context accordingly, or your identity context accordingly. It takes a few bits of configuration, but once again, the simple path using one database, we have the context already. We just need these three lines. And then we can add Identity Services store application. And it will know that it should be looking to this database context for all its connectivity needs. Alright, so with all of that done, we can go over to our Package Manager Console. And when we have that open and running, we can change the default project as we know. We set it to data. And I'll say add My agree. I did user tables. Now notice I didn't do anything. I didn't create a new entity. I didn't The only thing I did to the DB context so as to make the inheritance change. But look at the migration file that is a boat to get generated. So we're getting a migra migration. Look at all of that big aggregation. By now, you should be familiar with migrations look like. I'll just point out what tables are being created. Getting one for the rules, one for the users. And you see all the fields being generated for the user. And all of those are relative to identity users. So just by seeing identity user here, we're getting all of these fields were getting rove claims, user claims and a bunch of other tables with a bunch of things. Some of them you may never even actually use any creates the indexes and any foreign keys. And then of course, don't just undoes all of that. That is what just changing the inheritance from VB contexts, that identity DB context, that is what the change results. Inside of the Package Manager console. If I do update database and allow it to have its way with the database, what you'll notice is in the database we get a bunch of new tube will say if I just do a quick refresh and look at the database and the tables that we have. You'll see that we have all of those new tables being added to the database. Just let that right there. You're putting in your user tables. It knows where to store the user information and you didn't have to sit down and write any custom code. And any custom code that you're about to write is really because of your business needs. Because he wanted to fix in most of these, but out of the box, identity libraries meet this soul Paul food and so easy. So when we come back, what we looked at is extending our user's table because right now the users stable, yes, it has a lot of columns, but you'll notice that they're not necessarily useful columns in terms of like a business setting or ideas. We have an ID, yes or no. I use a name and an email but we don't know the person's name. Don't know which use it. This is just based on their name, FirstName, LastName, even date of birth, anything you'd want to store both the user and just picture this application as an application will be used in accompany any company that you're in. You, they want to know who you are when you login. They don't want to be able to see all the information. Well, this is where it starts storing it. When you get created in this system, they usually put in order. That's when we come back, we'll look at how we can extend the table at will. 31. Extend Users Table : All right guys. So the last time we were here, we were looking at setting up the identity tables in our database. Now we need to know how we can extend those tables to take on different fields. We're going to start off with the identity user. It closes some fields, what I want more fields. An easy way to do that would be in the data, just create new folder. I will see identity so that we know anything in this hole is identity related. So I have a class, so you can name the class anything. So the most popular name you would see its application user. But once again, what's you name? It is up to you and your operation and your objective. Let's say application user. It's a public class that is going to inherit the character traits of an identity user. Identity users, the default user, I'm going to say, all right, well, you have everything that a default user has. But you also have, this is where we can start putting in String first name, last name. If you wanted to put in an employee ID, are still flight or anything unique to that person. So I'm going to stop at first name and last name. Date of birth, I think adding the date of birth would be a nice activity. Date of birth. All right, that's it. No, we need obligation user to be the default user class whenever we're doing our operations that we have access to the additional fields on the code side, but we also need to extend the database to actually be stored in these fields. So one startup, I need to change AD Identity core from just seeing identity user to know seeing application user code-wise whenever we're doing anything user, user related, rather, it will be using this datatype and give us access to those fields. For the database, we need to jump back to our context and later identity DB context nor by attack brackets that it should be using. And if you look the type brackets say give me the t user. If I tried card, Let's IV car would work. They're just wanting a class if I used car, no, the era shifts, he'd saying it cannot be used as a type parameter for t user. That's what it said. Remember when we're talking about generics and the data types, it says T user, where the user is of type identity user. So it has to be some entity that is of type identity user, like the application user which we just let inherit. So I can know, put application user there and everybody's happy. Know that the DB context knows that I'm using application user if I do a new migration. So I went to say I did user, I did more user fields as my migration. He's going to re-evaluate know and say, okay, I'm dealing with a new datatype. And this new data type has columns I didn't account for, like date of birth, firstName, and lastName. Please go ahead and add them to the database. It's adding that column to the ASP NET users table. Those columns. When I do the update, finishes successfully. And then if I look back at my idea to be stable, after a quick refresh, I will know see my new fields nicely displayed in the ASP NET users table. First name, last name, and date of birth. That's how you can extend your classes when you are dealing with the user related operations. Just to see him, we could have extended identity rule. What if the rules stable didn't have enough information or as much information as you would have liked. All it has is a user ID. Sorry, that's the wrong one. You roles, roles they're ago rules has named normalized name, chronic organ system. I don't know what else you'd probably want to add to it, but I'm just showing you that the same way we can extend application user by the inheritance and then use it in place. Off is the same way that you can extend roles or anything that has the prefix identity pretty much in front of it. So all of what we've done is just configuration. When we come back, we will look at how we can set up our registration page and let users login. 32. Setup Registration Page: Guys, welcome back. The last time we were here, we were talking about actually letting the users register and having them login. So I'm just going to collapse everything we're going to buckle up to or what project I'm going to close all tabs that are not directly needed. And inside of our app, I can right-click, go to Add. And I'm going to see new scuffled item. Now under this dialog box, you'll see that there is a category that says identity. When I double-click Identity, it will do is it'll checks. And then it goes on to evolve into the screen where it says Add identity. You can override all files. So the thing is that when you get the template file is actually kind of, they're just kind of hidden from you because nowhere did we see any login or register pages, they're kind of hidden. But when we want to overwrite them, we can easily say we want to override off as or we can cherry pick the ones that we want override. In this situation, I would like to override the registration page and the context it should be relative to his car booking up DB context. I don't need to add the user class or anything else for no, All I want is registration. And then it can go ahead and hit Add. It will take awhile to do the scaffolding. Of course. When it's done, we get this README file. Okay? We don't really need that, but if you look, you'll see that we have a new folder called areas. And if you drill down, you see identity pages and then you get a few new voters. Don't do this register file. And if you notice, this is also a Razor page. By default, these uber is a pHs regardless of the project temperature using. So let's look at what register gives us the CSS. Html5 gives us a form where we get an input for email on footpaths where they wanted to confirm the password. We know that we have other fields that we need, so we can always extend this as we need to. In the register code behind it, you'll notice that it is injecting. Yes, it asks us for the DB context, but notice it is not injecting a DB context. Instead it is injecting what we call it a sign-in manager and a user manager. They are relative to application user. I'm just showing you everything is connected. The reasoning to see application user and not identity user is in the startup. We told it that when you add identity, anything identity related, use application users. So no degenerated code knows it's not identity user voltage is application user. Notice this didn't give an arrow because they could be used interchangeably. However, I won't go against the generated code and look at the fact that we have the sign-in manager as well as the user manager. So these are built-in libraries given to us by the identity core library. That's the lowest, the handle signing related operations and anything basically user operated get user related, sorry, operations, getting a user, changing something about the user, etc. So everything here is being injected and you'll see that there's an email sender. We haven't implemented any e-mail services just yet. This is really just a place holder which can be overwritten later. We also get the eye logger, which is relative to the page that we're on. If you notice at the top we have this attribute that's his allow anonymous. So we look more at attributes later on when we're discussing how we can allow on Auth0 authenticated versus certain parts of the application versus how we can lock down certain parts of the application. So let's move on. In this model that was generated for us, you see that we have buying property above this input. So this is a pattern that we've seen before. If we look in our pages, we see that for the Create, we had done something already, generated something similar to that property over the entire model called car. However, in this situation, you'll notice that model is actually input monitor is actually defined right here inside off the page, a class inside of us Ugandan buff patterns, but I'm just showing them to you that even though it looks slightly different, It's the same thing. You'll have a class. And this class has the same attributes that we had put required. This is anemia address, this is a display name we want we had used all of those before and it's just a property called email where seeing some other ones, but they're the same things. We have the string length verification and this one is a password, and then this one is saying it's a password and it should compare with password up top and show that error message if they don't match. That's all. That's why we only have three fields in the input model, which is being used on the form. That is why the form is binding to input dot email input dot pass or it. Input dot confirm password. Then outside of all of that and get, it just takes a return URL, we can get rid of some of these lines of code like this, external logins and so on. We don't necessarily need those. At least we're not going to be setting them up in the scope of this course. But after the form is submitted, we see here that if the model state is valid, is valid is relative to, once again, all of these attributes up top. We create a new application user passing into details coming from the form and username and email address. And then we create. So here's our user manager. Dot create Async, a new user using the password that was entered. Know unimportant B2B or passwords is that you never store passwords in plain text in the database? Yes, the user can only type in the word when you're typing in pastor is the only type in the words and the numbers as you know them. However, if you were to see what was stored in a database, you should never ever recognize it. That is, That's defense number one against hackers. Hash your passwords. Know the good thing about this libraries that by calling this method, all of that is done for you behind the scenes. So you actually don't even have to worry about the security of the password storage once you use this method to create the user record and give them the password as entered by the user. If the person was successfully created, you just logged that and then we generate the code. So when we talk about confirm your e-mail address and we'll send you the e-mail. This is the code that generates that kind of talking behind the LINQ query is linked to confirm. All right, So please confirm their cones by clicking here. That's what that confirmation email looks like. Once again, we don't have any immune services running, right? And also we can bypass that bit for no. And then they say if, and then here it is, require confirmed account. Does that look familiar? Because remember when we configure it identity core, we said you don't, we don't have to require it. Here. We're seeing if the options said it should be required. Then we read into the register confirmation page, which is just like a shell page to pretend as though you were clicking the same link here. Otherwise, just go ahead and sign them in. So that's what that's signing async is four. Then we get all the errors. If it failed to create the user, we get the errors and then we send them back in the model state to the page. That's got multiple. I just wanted you to understand what this code is doing because it can look overwhelming, but we need to pay attention to it. You'll see that all of the variables, all of the code is written in such a way that if you just read it, you can actually follow along with what is happening at each point. Let us test or a distribution page. What I'll do in our shared layout page. Oh, I noticed that we also got this login partial. Miss that point. This login partial came with the scaffolding activity and this login PowerShell has the the links tool. See here it is register or login. Login partial is actually just giving us the links we need for the login or register. And if we were signed in, it will say hello, signed in user. And please logout. What I'll do in the layout is used that partial in the navbar. Going to inside of this div that already has the navbar. And all we have to do is please the partial intrusion, partial name equals login partial. All right, underneath that, you will section. Let's state this for a spin control. If the first thing is agreed me is an era of boats, no service types that as an injection error. And it's soluble to signing manager for application user know the sign-in manager is being used in the partial for login. It's saying that this has not been registered. Know going back to the startup, what's I went to do is modify the library or the function I'm using here, I'm using AAD identity core. But if I just type in identity or CDF, I'd identity versus AD Identity core iodide into TTX two type parameters, and it sets it up as the default identity, whereas identity core sets of certain things. But I believe that what happens is that with identity core, you have to register your list of on-demand identity with just register everything. Whereas with identity where I have to say, well, the USU's identity core and I also want this service and that, that service, instead of complicated in the configuration, I'm just going to Tick identity core and use AD Identity also took out the line that added the rules because iodide entity wants a user and our role type in the type brackets. So that's what it's going to look like. This line is no services that added entity t user. So if you look at the overloaded ones, something of type T user and something of type T rule. So to user would be identity user, our application user in this case. And identity row for the t rule of type. With all of that done, let me control F5 and try again. No or obligation is loading. And not only is it loading, we know how the tool links in the navbar. So if I click register, it is no telling me about the eye email sender. So remember I said that we're doing that's a service that we don't yet have. That's no problem. What I will do is not injected, so I'm just going to remove it from the injection here and come into tote and I'll leave it wherever it's being used, nowhere. I'll come into those. So anywhere that the email sender objects was being used, just comment that told for later use. So that should solve that problem. Let me control F5 again. And this time when I go to register, it works. Alright, so you see here this is what the form looks like. We get email password, confirm password, and then something about using another service or register. Remember that we have this file, so we can modify this registration form however we want. For instance, I want more fields in their distribution. I don't want just the email address and password. We know what it is that we have username and we have emailed. Those are two different fields. However, the way the form he sets up brand now it's just asking for an email, but it will use that in both EMEA and username fields. It's up to you if you wanted to separate them and if not, you can leave it as is. However, I do need the first name and the last name to be added to this form. So I went to jump back over to my register form and I'm going to add more textboxes. So before the email, I'm going to put in input dot first name. So all I did was copy the whole block for email and I will look up modifying forms already. So this should be rudimentary stuff for you at this point. I'm just seeing gene, additional ones that I created to firstName and lastName multi-cell them getting those red lines because firstName and lastName don't exist in the input object. What is this input object? If I Control click and jump over to its input model, what is input model? Input model is what had these fields defined? I can no see. I want my first name, my last name to be apart of the input model. Firstname, LastName. Once again, nothing special. I'm going to remove or change the display names. However, of course, the datatype that I'm validating is not email address for these two. There we go. Now our input model has been extended. Firstname, LastName, and whatever LLC tad. We also added it to the form and you'll see those red lines are gone. No. So everybody knows their role. And then the final thing I'm going to do is extend obligation user, but I'm not going to do that one. I wanted to at least register somebody without the data going in. And then you'll see how it looks when we get the cart data. I did. So let me control refresh again. Jump over to my register and you see know the formula showing more themes. So if I put in all of those and I'm going to say car Booking.com, Booking.com password. The password, but the fault is strict. Someone to say capital P at saying, it says totally already one. That's the buzzword there it is for your eyes. And I went to use that confirm password. If I change it, look at that, the password and confirmation do not match. So automatically we're getting that kind of feedback. If I put in something invalid as an e-mail address and try to register or does something invalid email addresses. Apologize. But here you're seeing that we have no user. Certain things are failing because they're expecting certain configurations that just aren't there. All right, That's no problem. As I said, as you see the errors, we fixed them. So that error is because the Tolkien generator that's being used by the user manager would have had to be configured from the startup. We're not ready for. I love that because we're not sending the email anyway. I went to comment, that's Alt also. I'm sure it's only got here because the user was created successfully. So if I look in the database in ASP NET users view data, you will see that the user was created admin at card Booking.com. That was not an invalid email address. So it worked regardless what you see here, look at the password. That does not look anything that the password I showed you on screen. Just know that's automatic hashing. We don't have to worry about any of that hashing. But if you notice the date of birth, the first name and last name were not filled in. Date of birth, obvious because we didn't add that field, but firstName and lastName were not filled in even though we provided data. So let us see how we can rectify that. Firstly, I'm going to put in the date of birth field on the form. And he really doesn't matter where you start to modification from as long as you get all the modifications done by the end of it, then you're good to go for date of birth. I would just set the type to be equal to date so that we can get a date picker in that field. Then input model. You are going to be date of birth of type datetime. I'm not going to make it required. I think I should make it required. I'm going to make it required because it's going to have a default value like we've seen, that we don't really want, right? So everything is required for you to register successfully on this website. So after we've done all of that, I want the additional fields to be stored in the database. I went to jump down to where it says, If the modern state is valid, then create a new user, giving the username email and the email address email. I can extend this and see and dear first name should be input from the form dot first name. This is something that we've done before. We build on what we want. Last name is equal to the input dot last name. And date of birth is equal to input dot date of birth. There we go. After doing all of that, what I'm going to do is test, but I'm seeing that of an easy here because I created date of birth as a date. I apologize, that should have been indeed time. So notice we have two changes to me of the change what wolves into the database. After we scaffold that field in the database. And we have to be mindful of that. But I think we can still get through this operation because the database should just convert that to a string anyway when it gets it. So let us try this again. Let's jump over to register and Tyrone Cooper change that today. For editing your ys are testing reasons. I leave that and I'll use my password at saying one or just use something. Birth 123, no problem that was in my clipboard. So I'll just reuse that. We click Register. Okay, parsers must have at least one. So you see that's the password strength at work. That's why I said p at sign a systole or D1, reuse that click Register. They're saying that they do not match. So let me try that again. Register. There we go. So no, it's even asking me if I wanted to see if the password just see if we can move along more quickly. But you see register and login there still not changing because we're still in the process of developing our application. No problem. But at least we see that a registration worked. That's one. We'll go through it without errors. And if I look in ASP NET users table again, I'm going to see additional fields have been added. So now I'm going to see my date of birth, the first theme and the last name. And everything is starting to come together nicely. 33. Setup Login Page: All right guys, So we're doing we're making good progress. The next step is to set up the sign-in page. I'm starting off with this starts or because there's still some configurations. Now it needs to go in. For our sign-in stuff. We're talking about what we call authentication. Authorization means can you do this? Authentication means let me prove you are who you are. When we sign in, that is when we authenticate. However, what we can do after we sign in is, are we authorized to do it? Although the box we have the middleware being used already for authorizations are at top of that. I'm going to add another line that says use authentication. This is what is really going to let that sign-in manager start working the way we want it to work. Another thing that we want to do is in the configure services and went to say services dot add authorization. So that we know that that service is being used whenever an application starts up. So with all of that done, let us set up our sign-in page. Now, once again, you can configure your registration page because this is the form to one side, it's only taking up four spaces. And then we have this other div to the mixed sides on both additional sign-in options, blah, blah, blah. That's taking up six. It would make it 66. He could make one smaller. You customize it as you wish. By now you should be comfortable enough to know a whole, to extend the form, hold to me the buttons customize and stuff like that. So I'm not going to spend too much time doing that. What we wanted to do, however, is add the sign-in page. I can right-click on areas again, click Add, and go for a new scuffled at item, click on identity. And then after he gathers all the information it needs, is going to give us this dialogue box that allows us to simulate where is it login. There we go. So we have that login page. I'm just going to take the logo pH also login. We have logos. And once again, you have a number of pages, you have changed paths or the forgot password. He can implement a number of things and a lot of the code out of the box is quite resilient. However, I'm just focusing on the ones that are absolutely necessary to get through what we need to get through. Login and logout. Again, our DB context is the database context class, and then we go ahead and hit Add. When that operation is done, it reopens the scaffolding. Read Me, but then we see we have the login and logout pages. So let's look at the logo first. Why did I take a logo pH? Well, all this is going to do is say, if the user that is here is authenticated, then although them to click logos, what happens with nucleic logo when they do that? The same in Manager log salt and then returns to the URL. That's what the logo page does. The login page, It's a simple form. Give me your email, give me your password. And do you want me to remember you? If not, well, whether you do are not. Let me go ahead and log in. It's automatically generating links for I forgot password. We didn't see it on that file and we're not necessarily going to implement it. No, that's fine. But you forgot your password register as a user are recent e-mail confirmation. So all of those things as well as this next section to the right, how about alternative login options? All of those things came in this form. So the login code behind is very similar to the register. Any of the allow anonymous, low people who are not authenticated to reach the speech. Then we have injections for our user manager and sign in Manager. We have the same kind of format with the input model. And the input model is being used here to just stay the e-mail and the password and sets apart remember me, On get, we just load the page pretty much so it's simultaneous external logins. We don't necessarily need to pay attention to that in this scope of this course. But when you click Login, let's look at what happens if everything is valid. We go and ask the sign-in manager to sign-in using the password given the e-mail address, the password provided. If the person said Remember me. And if we have local enabled, local means that if after a few failed attempts, they should lock your county, I'm sure you've encountered that. All of that is built-in, in this very powerful library. This course is not enough time to go through all of the capabilities of this library. That's why I'm focusing on the big, bigger and more important things at the moment, right? After we tried to say if it was a successful sign-in, then we read Erich, the return URL. Otherwise, we check if it is, if it requires two factor authentication and we spring that interaction. We don't have that implemented. If the user is locked totes, we read them that we don't have that implemented. And if all else fails, then we return with the model error, seeing string dot empty as the key. It was an invalid login attempt and we return to pH. If it gets this far, it means it didn't work. Nice and simple. So let us go ahead and test or sign-in. Now we already have some uses created. I'm sure you and crazy registering a number of users since he got the register to work and you see, I had one sign, didn't just know, I just logged out. So let's try this no login. We get to sign-in page. Great. I did say was admin at car Booking.com. Let me I think it should have a four on the end of it, but let me try and login. And you're going to see that it says invalid login, attempt it check the database. It didn't find that username or e-mail and password combination at all. Let me put in what I think that email adverse was even though our purposes just make a better one to unshare again. But let me try this again. Click Login. No, I'm seeing something else. I'm getting this error board data being null. All right, so I went into debug mode and rerun that operation. And this is the error I'm getting, which makes a bit more sense. And I figure it's complaining about this because we change date of birth, date time, but the database tools thinks shrinks. So that's an easy fix. Just add a migration, changed DOB to date type. Let it do the migration. Migration is the TEN noise and alter column for that field that at that, so update database. It is seeing it failed because I am not allowing nulls. So remember that whole conversation about datatypes and notes. That's fine. I'm not going to pressure pressure too much what I'm going to do since we're still in the experimental phase. And you can do to whatever users you had created. Just find all of them. Delete. Alright, at this point, that's important, that's why they're there and therefore testing. So I'm removing all the currently created users and then I'm just going to rerun. So sometimes you don't have the luxury of doing that. But we already looked at how you can take steps when you can't remove all the records you have already when you wanted to make such a change. So anyhow, they update was successful this time. So let me just Control F5 and try this again. I'm went after register firstly and I'll do it properly this time. So date of birth. Just do today admin, car Booking.com. That is the buzzword after confirmed this password just for your eyes, that is the password. And then we click Register. Know, I'm going to save the password and look at that hello Admin, not carbocation. Know that we included the ad. All use authentication and the service for AT authorization in the startup, we actually start seeing the changes on the user interface. So let me log out and I'm going to login now. I'm going to use the same admin, a car booking, same password, click Login and looked at that. We're logged in. Logo works also. You see, there we just solved that problem. So now we've fixed the registration problem going forward. You should not have any of those programs. Again, we know how to login and logout at-will. The next thing would be how do we prevent users who are not logged in from reaching to these pages? Because at this point, logging in doesn't make any difference. I can go anywhere in the application. Without logging in. We need to look at how we can tie it on our lockdowns, access to certain parts of the application for unauthenticated users. 34. Setup Authorisation : In this lesson, we're talking about whole weekend restrict access to different parts of our application for authentic, authenticated users and on authorized and vice versa. Now this sounds more difficult than it really is. And I'm going to show you how easy it is to accomplish this. No, We do have login and registration functionality open running, but we need to be able to manage these pages. So anybody should be able to get to the homepage comfortably. But if they click cars, they should be forced to login before they can proceed to look at the cars and easily to get done. And it's very easy way. Let me just close all tabs that are not important at this point and collapse anything. If I don't want you to be able to get to the list of cars. All I have to do is above the page code for the cars. Add an attribute that says authorize the missing using statement. That's it. I told you it would be simple. So let us take a look at how that works. So this is over the index page for cars I did authorize, which means that I should not be able to in an unauthenticated state, click on cars and see the list of cards. Looks, look at what happens when I click cars is going to, okay, Well, okay, this is anticlimactic, but you see it's not behaving properly. It's actually trying to get to the login screen. Now I'm going to jump back over to the application, and I strongly suspect that I'm going to have to change my configuration. Again. This is the ones again, this back-and-forth. It's good because when you see these kinds of arrows, it helps you to infer where you need to go to solve these problems. When we added services, remember that first we add identity core, and then we saw that it didn't come with certain things out of the box, which is why we change it to identity. Those things it didn't work well with. Out of the box started to work nowhere seeing another thing. The issue with the arrow we just saw is that it is looking for the login page at a certain location that it doesn't exist. That's because identities just going to say look in that location. However, I would want it to look in the default location based on the scaffolding. So I don't want to do a lot of configurations and alter change the normal flow of the application. For that reason, I can, instead of using identity or identity core, I can use default identity. If you look at this one, it says adds a sense of common identity services to the application, including our default UI, which would be where we have scaffolded our stuff. That's the default location. Token providers. Remember, complete when we're registering our boat, the whole token provider and it walks for teacup or a toy, it's missing and we have to include it. It's automatically included with the default options and configures authentication to use cookies. That's what I'm going to do. Add default identity. No, I'm getting this error because I'd defaulted entity at similar to identity core words only takes t user, which means I have to manually come down here and see add rules. Again. Add rules, and then we give it the identity rule. Let me put it in brackets. There we go ahead, entity rule, close. No, we're using the default library for identity. And this one, like I said, is going to include certain defaults, Alt off the box that other things did not necessarily. Let's take another stab at this experiment was that we have added authorized the car speech. I should not be able to navigate there without having logged in before. So if I click cars, look at that, it's just automatically redirecting me to the login page. So because we didn't have the default, it wasn't looking in the default location of the identity folder to find the icons and login. So that actually omitted that part, which is why we got this page. I'll never show you something or encodings an error without explaining why we got it and how we fix it. So now that we are on the login page, Let's make sure that's our login functionality still works. Yes, it does. Here's our hello and no, we can't see the page, so nowhere authenticated and we are authorized to see the page. It would be kind of tedious though to say, Okay, well, after lockdown to edit and the details and the Delete, because at this point, if I wanted to edit a car and I remembered the URL for editing our car. Let's see, I'm not authorized and I go to cars and not authorized. What's I was standing over somebody's shoulder while it was. Editing our car and I remember the URL. I can actually just put in that URL and bypass the whole authorization to get to edit car, which is wrong. At that point, I would have to add the authorize attribute over every single page that I want to let them set up to do, to create, I'd have to do two more details. Edit that every single one of them, which is not necessarily, I mean it works and it can be practical in a small application. But to me, it will just get tiring easily. And it's easy for somebody to forget to place that code above the pH code. What we can do is do it on a global level. In our startup Weekend, add this bit of code or add a Razor pages area. You may see varying code between how it does it in Razor pages and if you've ever had to do it in MVC, and as you see in a whole bunch, you know, there are so many ways to accomplish the same thing. Just find the one that works for you and is best for your context. In this situation, all have to do is see arteries are pages. Start to apply that same option. Object to accept. I'm just calling it o instead of options. So all lambda expression. And instead of that I'm saying all dot conventions, dot authorized folder, slush. There are a number of things you can authorize. Authorize the area you can authorize a full-day, can authorize a specific page. If you have maybe a specific page that you want to have specific rules is different from the other pHs or a specific folder to play by different, he can add all of those. They're called conventions. Norm just adding one global convention to anything after a slash and seeing you are supposed to be authorized. So this is going to automatically runtime basically add that authorized filter over every single page in my application. The only way to bypass it is by adding or allowing anonymous. So I'm going to show you that right now. So if I remove that authorized from the cars page and a Control F5, let it run. You're going to see that I should have landed on the homepage. It needs me to sign in if I tried to go to mix, it wants me to sign it no matter where I go, I have to sign in. But then if I go to register, it allows me to see the redistribution page. That is because the filter called a low anonymous is above the register preach, right? So if I jump in and look at already store, you'll see a low anonymous above it. So if I add that to, let's see, regular index page. Remember we started off with our index page where we had all of our wonderful quote from more basic web div class. If I wanted the user to London, at least the homepage without any butter. But everywhere else they need to sign in, then all I have to do is say allow anonymous. So by doing that, if I refresh and go over to the homepage, the homepage renders just because I said hello Anonymous. However, if I tried to go to cars, I cannot get there. If I tried to type in a direct URL to cars slash edit with the ID 14. I have to log in no matter what I do, I cannot go anywhere either, right? No privacy. It wants me to login to rectify that. I just need to go above privacy and allow anonymous access. Sudden makes him I click Privacy. It will actually bring me to the privacy page because anonymous persons are able to view it. If I log in and then I try again, then okay, homepages, good cars, and everything else is available for viewing. So that is basically how we can lock down or application and restrict unwanted access to sensitive areas. 35. Add Authorisation : All right guys, so I think we have done a good job of securing our application to this point, we have setup successfully the registration and the login, and there's so much more we can do. We could get into roles, we could get into restricting users based on certain policies and claims. There are so much, so many things we could do. But sadly, I don't want to overwhelm you with all the information and all the scenarios and so on. It's better to absorb this much NO and experiment with it. And then you can extend on your knowledge as you need to. For now, we can just do a quick review of what we implemented. Starting with our identity user, the application user class. When we were setting up our identity library. In this project, we had to inherit cheesy inheritance for the DB context of identity DB context. And then we set it to inherit based on the context of application user. Application user was our custom class that we meet to inherit from identity user, where we put in additional fields that would extend the users table in the database. So far we didn't write any custom code to handle creating the user or hashing the password or even login capabilities. All of those things were given to us out of the box. And the width, the leeway that we could modify them off course. So after doing all of that, we scaffolded the changes with a few migrations, had a few field migrations be some changes, but we went through all of that. And then we made sure that we configured identity in our web application, which we also also went through cycles of identity versus identity core versus AD default identity, which is the one that we said that Louis, because it came with the most pre-packaged libraries based on what we need to do. So after doing all of that, we went ahead and made our user interfaces, modified some of them. For the registration. We had the comments, thoughts, all the code because it was not necessarily applicable to our current scope. So we remove some of that code. We put in the login and logout functions and pages. We also got a login partial courtesy off the scaffolding which we added to our layout page, which gives us access to the register and login links. Now with all of that done, Zoom bullets are good changes. And see that we added login and functionality to our application. Our teammates know exactly what to expect when they get the latest code. So I did log in and add functionality and then we just commit all and sink. That's it for this section.