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.