Hi everyone and welcome to this course where you will learn and master asp.net core web development skills and join me in building highly scalable data-driven and pay-centric asp.net websites using Razer Pages. I will be the instructor for this course and together we will build an asp.net core website from scratch based on the popular Razer Pages framework. Asp.net has evolved over time, many of us have used the very famous MVC pattern and created websites using the asp.net framework, as asp.net has evolved, the way we used to create websites has changed, we Have the latest and preferred way to make web applications using the Razer Pages framework.
In this course, we'll build a highly scalable blog application from the ground up using asp.net core razor pages. We will learn an overview of asp.net core and Razer Pages framework. We will then proceed to create a new asp.net core Razer Pages project and browse through the files and folders we got in the new project We will start defining our domain model for our application We will use the most popular Object Relational Mapping Entity Framework tooling and connecting our Razer Pages web application to a SQL Server database.
- We'll first start with the basic thread operations, creating read update and delete operations on our database.
- We will also learn how to use Entity Framework to view the initial data of the database. We will learn about routing and look at different routing techniques for Razer web pages.
- We'll learn the Repository pattern to read and save data into a database, and we'll learn how to fetch data and submit a form on page load.
- We will also display success and failure notifications on our web pages.
- We will use the most popular Bootstrap CSS framework to speed up the web development process while maintaining a consistent clean and responsive look for our website.
- We will also create a Web API controller in the Razer Pages application and we will call the APIs using JavaScript.
- We will learn and implement asynchronous programming throughout the code.
- We will implement a third party, a rich text editor, to create content for our application.
- We'll add authentication and authorization to our project using Microsoft Identity and the sign-up and sign-in functionality.
- We will implement multi-role authorization where we will have roles for user admin and super admin.
- We will also implement the ability to manage users.
- We're going to talk about these topics in a very hands-on approach so that each concept emerges naturally with the practical website we'll build Let me walk you through the app we'll build in this course and we'll create a fully functional Application development blog site.
- This will be a site where we create development related blogs, and people on the internet will come to our site and look at those blogs on the home page.
- We have all available blogs available to us as a list, we also have categories, also known as tabs for these blogs on our website, these tabs are used to navigate to similar content, for example the ASP web tab gives us all the blogs with blog tag asp.net. In it, users can view the details of any blog by clicking on the read more button. This will take them to the details of the blog routed using the URL handle which makes blog SEO friendly to search engines like Google and Yahoo as well as blogs.
- The detail page also has a feature that shows how many users liked this block. As we scroll down, we'll get the ability to view comments on these blocks, as you may have noticed likes and comments appear on the screen. But they will only work if you are logged into the app as a regular user who visits our blog.
- We have functionality where users can register themselves using a registration page. After successful registration, they can log into the application using the login page. After users log in, they can browse the site as usual. But now they have likes and comments on blogs.
- In addition to normal users, we implemented two other user roles. We have admin user and super admin user, both admin and super admin user can log into the app, after successful login they will see another navigation which is only for admin and super admin. Using the admin feature, administrators of this blog can create new blog posts. From here, they can access a rich text editor that they can use to create content for this blog.
- We've also implemented the ability to upload images from these blogs to a third-party cloud-based image hosting provider. Admins will use this page to create new blogs. They will see all the blogs they want to manage using the blog list page, from here they can view the details of any blog and update any of them. They can also delete the blog using the delete button.
- Another function of admin is to manage users. Our user pages are only available to administrators and super administrators. Using this page, they can view and delete users. We also implemented the add user functionality, but using a popup model.
This will be an amazing tutorial and by the end you will have mastered creating scalable asp.net core websites using Razer pages. I'm glad I did, and I hope you'll have fun with me. In this talk we will create a new asp.net core web application from scratch. This will be our blog's web application, for this I have created a folder called bloggy and under this folder I want to create a .net web application.
Visual Studio takes a few seconds to create our new application.
In this talk we'll learn more about projects and the files created as part of project scaffolding. Let us understand them one by one.
At the top, we have our solution.
A solution is an architecture for organizing projects in Visual Studio. A solution can have multiple projects where we can also consume each other.
Below the solution file, we can see that we have the project file. The project file in our example is "Bloggy.web". Similar to solutions, projects are structures for organizing files and folders within a single project. If you double click you can open this "project.csproj" file. You can see the properties of the project. From our example, we can see that we are using ".net version 6" as our target framework. We have "nullable" enabled and "ImplicitUsing" enabled.
When you add nuget packages to our project, they also end up as a reference in this project file. Now let's look at the "launchSettings.json" file which is under the properties folder over here. As the name suggests this Json file has configuration launch information of this project. Stuff like profiles and application URLs reside in this "launchSettings.json" file.
If we use the drop down we can see that we have different profiles. The currently selected profile is the "Bloggy.web" which if you see in this Json file over here is this profile.
You can go ahead and choose a different profile, or change your default browser, if you want. Currently I use Firefox as my default browser.
If you go back to "launchSettings.json" we can see the application URLs for the different configuration files that we can access the IIs settings. Our application URL is localhost 9100. For the "Bloggy.web" profile, our application URLs are localhost 7037 and localhost 5037, based on the https or HTTP version. Your project may have a completely different URL so know what URL your application is running on. Find it after "launchSettings.json".
We have "wwwroot" folder here. By default, static files such as HTML, CSS, JavaScript and images are assets that an asp.net core application serves directly to its clients. Static files are stored in the project's web root directory, also known as the "wwwroot" folder. This means that any files under this folder are publicly and directly accessible by your browser clients.
Now let's talk about the Pages folder here. The main folder in any Razor Pages project is this Pages folder. In the pages folder all the pages needed for our project are available. In the shared folder, we can see two files "_Layout.cshtml" and "_ValidationScriptsPartial.cshtml". cshtml stands for C# HTML. As you can see, the names of these two pages are preceded by an underscore (_) symbol, which means that these are partial views. Partial pages are like user components, which means they can be reused in multiple places in our application. Inside "Layout.cshtml" there are different things. It is like a master page that we can use for different pages. In this file we have header, body, footer and some scripts at the bottom and some css styles linked to it at the top.
In this "ViewStart.cshtml", we can see that we have defined a layout and we have made the underscore layout file as our layout file.
All application settings are contained in this file. Any changes made in this "appsettings.json" file will require restarting Microsoft IIs Administration. In "appsettings.json", we can see that there are some details available such as logging, defaults, etc.
We can also add the connection string here while creating the application. Keys related to security dependencies can also be added here.
We can access all these variables in the program.cs file using dependency injection. Finally we have this program.cs file. For asp.net core 6 projects, you won't find the startup.cs file.
If you are coming from a previous version of .net, you may see that there is no startup file, because now everything is contained in this program.cs file. The program.cs file is the new location where you need to register dependencies and middleware. The program.cs file is the entry point of the application. This will be executed first when the application is running. In this file, we start by adding services to our container. dotnet supports the dependency injection software design pattern, a technique for implementing version control between classes and their dependencies. Dependency injection in dotnet is a built-in part of the framework. We can inject our service into the .net core DI container by accessing the service collection in the Builder object. An example is adding razor Pages as a dependency of this project. Dependency Injection can be a bit tricky if you're just starting out, but trust me, when you fully understand it, you'll love it. So don't hold yourself back from learning anything you can understand about dependency injection, especially in .net core. Finally in this file, we configure the request pipeline here. By using the request pipeline, we add middleware, which is software that is assembled into the application pipeline to handle requests and responses.
These are middleware that are configured by default in our application.
These are UseHttpsRedirection, UseStaticFiles, UseRouting, UseAuthorization, MapRazorPages.
The order of these configurations is very important. Finally we run our application using the app.run command.
In this lecture, we'll continue creating the domain model for our blogging application.
We'll start with the administrative functions first. Administrators of this blog application will be able to create blog posts and add tags to those blog posts. The tags will be similar to the hashtags we've been seeing and will serve as categories for these blog posts. Blog posts here will have structure. It will have an id, a title, a page title and name that will be used as the chrome tab, it will have content, which will contain the entire content of the blog post, it will have a short description column, and it will be something like the summary field It will have a Featured Image URL which contains the URL of the image we will use for the blog post, it will have a URL handle which will be a relative path and we should be able to go directly to that blog The website URL of the article, which will have a publish date, author name, and a visible field which is true or false depending on when the admin has to show this information to the user. On the other hand, we have the tags table or tags domain model . This will contain the ID, Name, and Post ID, and you can see that the ID column in the post is connected to the Post ID column in the label. So this way they are all connected.
Let's go back to our application and create what we just saw. We have to create the domain model, for this I will first create a folder. So I'm going to right click on my project click add and create a new folder. I'm going to call this model and inside this models folder I'm going to have domain models so I'm going to right click add and create a new folder again and I'm going to call this domain.
So this domain folder will contain my domain models. Create my first domain model, which will be the "BlogPost" domain model. I'm going to right click on the domain folder. Keep adding, I'll pick a class. So this will be a new class, I'll name it "BlogPost". I'm going to click the Add button, now it's time to add properties to these BlogPosts. To add a new property, you can type it all in, or there is a shortcut to add a prop property, then if you hit tab twice, it will give you that property, and then you can change the property type and name if you want. So the first attribute we need is the ID, which is a commodity. So the type of "Guid" and the name of the property will be Id. After that, we will add a Heading property of type string. Then we'll add the PageTitle, which is also of type string. Then we have the full content of the blog post, so the name is Content. Then we have the ShortDescription. Then we get the FeaturedImageUrl as a string. Then we have UrlHandles. After that, we have the PublishedDate of the datetime. Then we have the Author type, and finally we have the Visible property, which is a boolean.
Now, when we create this domain model, we can see the green squiggly line appear under the property,
it means that the non-nullable property title or any of them must contain a non-null value, this is because in .net 6 or C#11. If you open the project by double-clicking, we enable nullable properties, and that's what tells us that these string properties can never be null.
But it's up to your domain to decide which attributes can be empty and which can't. So I've kept all properties non-nullable, which means you have to enter a value for the app to work. Otherwise it will display a 400 error.
After this we have to create the domain model for "Tags", then I'll go back to the Domain Models folder and right click to add a new class, I'll name it "Tag". Click Add, here we have three properties, the first is Id. So a Guid type and property name is Id. Then we have a property of type String and the name of the property is "Name". So this will be the tag name, and we end up with the blog post ID that uses that tag. So another property of type Guid will have "BlogPostId" and that Id will be the same as this domain model Id. So if you look at the convention, we use Blog Post as the domain model and then Id because that column is the Id. With this our domain model is ready.
Now that we have created our domain model, it's time to add the Entity Framework Core package to our solution. To do this, I'm going to right click on dependencies. Go to this to show options for managing nuget packages. This will open the nuget window for me. I have to come to the browse section here. Search for and install both packages. The first package I'm going to install is this one called "Microsoft.EntityFrameworkcore.SqlServer". So I'm going to copy that and paste it into the browse section, and I'm going to select this package at the top. Click Install. After installing this package, I go back and search for the second package, which is "Microsoft.EntityFrameworkcore.Tools". I will again go to browse section and search for this package from there select this package and click install.
Now we have to add a connection string in appsettings.json
We'll add a ConnectionString to our SQL server and provide the name of the new database we want to create. For this, I'm going to the appsettings.json file. Here I will add a new property for "ConnectionStrings". So inside the double quotes I have the connection string property and I will add a new key value pair to the object. So the key is the name of this connection, this can be anything, but remember to use that too later. So the name I give to the connection will be "BloggieDbConnectionString". Then the value of this BloggieDbConnectionString will be server equal to and this will be the name of your server installed locally in your computer. For example, I opened SQL Server Management Studio. This is the name of the server I installed as part of the setup. So I'm going to copy it and use a server name that I can connect to locally. Also browse the database, if any. So make sure your SQL Server connection or SQL server name is appropriate for your machine, then use that name and I'll paste it here. so the server name is this after which i will put a semicolon and then i have to give the name of the database so database equals now our application has no database so you can provide any database name and entity framework code will use that name to create new database. For our application, since its name is Bloggie, I can give it a name of "BloggieDb". Finally we have to write trusted connection is equal to true. So trusted underscore connections equals true. So this is the connection string we have to add in appsettings.json
We have now added the connection string to our SQL Server database. We have to inject our database context class into our application's services using dependency injection. So whenever we have to talk to the database, the application handles all the connections and instances neatly and provides us with the data without a hitch. So we're going back to our application and this time I'm going to open the program.cs file where we do all the injection. After this line it says "builder.Services.AddRazorPages()". I also want to add a dependency of this database context in my application. So I will use the same. I will use "builder.Services.AddDbContext<>". I have to provide the type of the database context, in our case we only have one type at this point, so I will use "BloggieDbContext". I will press (Ctrl+dot) and use the using statement bloggie.web.data. Since the Bloggie.DbContext comes from the data folder, I can pass options to it. So I will say "option=>options.UseSqlServer" database for our application, so I want to tell UseSqlServer the option. So I'm going to use the method of using a SQL server, which we don't currently have. So I will press (Ctrl+.) to bring in dependencies, I am using this package Microsoft.EntityFrameworkCore and this method UseSqlServer(). It requires connection properties. This is a string type connection, it needs to establish a connection between SQL server, we store the ConnectionString in appsettings.json which we did earlier. So I'm going to extract the ConnectionString from appsettings.json here. For this, I'll use the Builder again. So I would say "builder.Configuration.GetConnectionString()", this method has an overload that takes the name of the ConnectionString we want to extract, and if we go back to our appsetting.json, the name of the ConnectionString is this. So accept whatever name you define. So I'm going to copy it and paste it as a string. I will save that. This way we inject our database context class in the application's service. So whenever we want to use the database context class, we can use it from the services collection.
Now we will create our database using Entity Framework. We will run the ingress framework core migrations to create this new database. To run Entity Framework Core migrations we have to run two commands. So let's open the nuget package manager console, for which we have to use tools. Then nuget package manager and in there click package manager console. Now we have to run two commands. The first command is "add migration", which creates a migration for us. So if I write "Add-Migration". This will be the first time we create our database. So I can write Add-Migration "initial migration". We can then press enter to start the migration. What happens behind the scenes is to look at the database context file for the classes we have in the data folder, and then create scripts in C# language using the database set. This way Entity framework core can use it to execute it as SQL in our SQL Server database.
After the script runs, we can see that a new folder called migrations is created. We have this file for initial migration. We are also open here. It has two functions, an up function and a down function. This is the file that the Entity Framework code uses to create new databases or edit new tables.
So here it has everything it needs to create this new table called BlogPosts and a new table called Tags. It also provides the primary key of Id and the primary key of BlogPost which is Id. Now we have created the migration. So now let's create the BloggieDb database. So I'm going to open the package manager console and execute the second script, which is to Update-Database. So I'll paste it and execute it. It checks the database with this migration file, then executes anything that doesn't exist or is different.
So the migration has run successfully. So now it's time to confirm that the database has been created. So I will refresh the MS SQL Server database. You can see that there is a new database named BloggieDb. It's the same name we gave it in the appsettings.json file, and if I expand it and go to tables, I can see the two tables I want to create, a BlogPosts table and a Label table with all the columns we want. So we already have the database and tables created for us.
in the next section we will create new web pages so that we can perform crud operations on these tables
[Music] welcome to section 3. in the
previous section we did a lot of groundwork in
creating our database and tables in
this section it's all about using them we
will create eraser Pages for our
application and we will perform credit operations on our blog post table using
Entity Framework in this lecture we
will make some
changes to our application to make it a
little more unique and different from what we get out of the box so let's
start our application to see what we
have at this moment I will use this button which says
bloggy.web to start the application you
can also use this drop down to set your
default browser so I have Firefox
selected at this moment but you can go ahead and choose the browser that you
want and once that is done this button
helps you to start the application with debugging so I'll use that
I have the website opened and on the
website I can see the header over here
which has two links one going to the
home page or the index page and the
other one is going to the Privacy page
then we have this middle section over
here which represents the data for that
page for example at the home page it shows
the data that is available on the home
page and on the Privacy page it shows the Privacy Pages data
after that we have this header we have
this footer which is fixed and common for all so you can see the header and
the footer Remains the Same and this
data inside changes as the page loads
if I come back to the application you
can see this folder over here which is pages and all the web pages or the Razer
pages that you see on the on the
website when it loads comes from here
we have the layout page and that has
the header the body
and then the footer over here so we
have to make some changes so that it looks a
little more beautiful than what we get
out of the box and to do that we will first change some header styles
with the website running I will first
remove these two classes which is navbar
Lite and background of white so I will
remove that and instead add a nav bar
dark so navbar hyphen dark and also a
background of dark so BG hyphen dark
and these are all bootstrap classes and
if you want to know more about bootstrap
and how it works you can go to get
bootstrap.com or just Google for
bootstrap and you can learn more about
bootstrap and how their classes work but
let's let's continue with this so with
that I will save my changes and the list
items for I will rebuild and apply
changes [Music]
with that you can see the the nav power
has turned into a darker color which
looks nice uh but we don't see the
index and the Privacy page which are somewhere here so let's go back and change
them so
instead of a text dark we can just
remove it or use a text light so I'll remove it to
see how it works and you have this
option to hot reload as well so if it doesn't work you can hot reload or you
can restart the application anytime so
I'll come back to the browser and if I refresh this
the home and privacy pages are now
coming again
we now have this good looking nav bar and
it's now time to create our first
eraser page so that we can start the
crud operations we will start by creating the functionality to add a new
blog post in this lecture we will add
the
functionality so that the admin can add
a new blog post using a form and for
that we need to create a new Razer page
so I will come back to the application and first of all stop this
and I don't need the layout page for
this moment so I'll close this as well now inside the pages folder we have all
other razor pages so we will create a
new page for this add blog post
functionality and this belongs to the
admin and admin only so I will create
this inside an admin folder so inside
pages I will create a new folder
called admin and inside the admin
folder because this
is the functionality only related to
blocks that means creating deleting updating and showing the blog posts so I
will create a new folder and call this
blogs you can also call it blog posts
so I have a new folders admin and blogs
so inside blogs I can now create a new
Razer page which will be responsible to
create a new blog post so I will right
click on this blogs folder add a new eraser
page
and I will select the Razer page empty
template and click on ADD
and I will give the name of this razor
page as ADD and that's it you can specify other
names as well but I'm just giving it
add
so now we have this new Razer page
which ends with DOT cshtml that means C sharp
HTML and this is the template in which
we will write our C sharp and HTML code
and if you look at it we also have the
code behind class which is tightly knit
to that add CS HTML so if you want to
toggle between the template and the code
behind class or the Razer page and code
behind class you can press F7 and it
toggles between the add cshtml to the
add cshtml.cs class and if you want to
toggle back you can press F7 again and
basically it acts as a Toggler so that
you can quickly switch between the two
classes now let's run our application to see if
we are able to navigate to this new
page I have my application running and
because I don't have anything in the
nav bar to navigate me to that page so I'll just use the URL to go directly so
I
will say slash admin slash users or
slash admin slash blogs because we have
the blogs folder slash the add page so
we gave the page name as ADD so add and
if I go to it we open the page there's
nothing to display but we can prove
this by adding an H1 tag over here
and I will say add a blog post
as the heading so I've saved it and
I'll let hot reload run
and if I come back and refresh I can
see add blog post heading over here so our
URL admin slash blogs slash ads goes
directly to our ad page and this Maps
easily to our structure over here
inside pages so admin slash blogs slash add
to be able to navigate quickly we can
also add a drop down over here and we
can say that's an admin functionality
so admin will have ADD users or or add blog
posts and show all blog posts links so
let's add that
I will come back to my code base and I
will open the layout page again and that
is under shared so I will open the
layout page and inside the header inside nav
I want to add a new list item along
with the home and privacy Actually I don't
even need privacy so I can skip this so
I can delete this and now I want to add
a new anchor element which will act
like the drop down for the admin section so I
will create an ally the LI will have
the class
of nav item so nav hyphen item and then
it will also have a class of
drop down [Music] inside the LI I will
have an anchor
element and this anchor element will
have a class
of nav hyphen link space another class
drop down hyphen toggle
[Music] and this will not have any ID
because that will just act as a button and
inside this anchor element or after
this anchor element I'll have another UL
which will act as a list of items so
iul and that you will will have a class
of drop down menu so a class of drop
down menu
and then inside this UL you will have
list items so again An Li
and inside the LI I will have an anchor
element which will have a class
and this class will be a drop down item
and now I can give the name to this
drop down item as well and also to this
anchor element over here so I will say
to this anchor element this will be the admin functionality so
I will say admin and along with this
class I will also have some other properties or attributes like the href
to be hash then I will have the role as
a button
I will have the uh the data bootstrap
so data hyphen BS hyphen toggle
is equal to drop down and finally I'll
just put it to the next
line area expanded as false so Aria
hyphen expanded
as false I will also give an ID to this
anchor
element over here which will match with
the uh the area labeled by for this UL
so that when I click and this anchor
element this UL shows up and all of that
is handled by bootstrap neatly behind
the scene so I will give an ID so I will
say this is the nav bar drop down for
admin
and this I will copy this and to this
UL I will say area
labeled by [Music] and I will paste
this ID over here
and finally the admin drop down will
have just one button at the moment so I
will say add blog post so this will be
a way to navigate to the add blog post uh
URL [Music] the last thing we have to
do is to add an href property so that you know when
we click on this button it takes us to
the add Blog Page and we know the URL so
it goes to admin slash blogs slash ID
which is the ad so the admin blogs ad
when we click this link should go to
that admin page and I'll hot reload it
and I'll also refresh my application
so as you can see we have a new drop
down over here and if I click this drop down we have the add blog post element
and if I click that it goes to the add
Blog Page URL
so we have added the functionality of
the admin inside the nav bar and also able to navigate to this new Razer page
in the next lecture we will go ahead
and add a razor form to this page so that we
can submit the values from the UI and
submit it to the backend
in this lecture we will create a new
form for our add eraser page and then
start submitting data from our from to
our backend so let's go back to our code
[Music] and inside here I will first
open the layout file
we have this render body tag which
actually renders all the content coming
from these Pages for example the add
page or the index page and it shows
inside the web page that you actually
see so it combines together to form the header footer and the main body area
so we have a container class which
actually restricts the view into a
section in the center so I want to take
this container class away so that I'll
only use it when I actually need it so
I will take this container class away and
save the changes and if I come back to
my application and refresh it you can see the content of
the add page now switching to the left
so it takes the entire space from the left to the right and you know there's
no containerization happening over here
what I want to do is I want to add the
container inside the header so that I
can make it visually more attractive
now I will come to my ad Dot cshtml
Page and I will add the container class over
here but before that I want to give a
background color to this H1 so I will create a div first
and to this div I will create a class
and give it PG secondary
and this is a very dark class or color
a background color so I will give it an opacity so BG hyphen opacity of around
10 percent and then inside that now I
will have my container class so div with
a class of container and then I will
add my H1 tag inside the
container so I will save the changes
and if I show you
it looked like this but if I refresh it
it now looks like this so we have a
light gray color behind the the H1 just
to make it more prominent and I can add
some padding as well so I'll come back
and give it some padding so padding on
the y-axis of around 2. and let's see
how that looks like so
refresh that and this looks good so we
have a difference between the nav and
the heading with a slight Gap so this
must be coming from the nav so I'll go back to the layout page
over here and let's see what the nav
has so the nav is
having a border bottom and a margin
bottom of three and that's causing the
white part to show in between so I'll
remove this and save the changes and what you see over here now should go
away so this is our heading and we will
try to maintain this look uh in all our
forms and now it's time to add the HTML
form and I have the bootstrap website
open as well and if you go to the
documents you have all the components that they provide and you can also have
the search functionality over here for
example if I search for forms
you can see the forms coming over here
and we can basically copy the HTML you
don't even have to learn all the
classes that bootstrap provides we just need to know what we can use from
bootstrap to
make it look like what we are trying to
achieve so for example this is an HTML
form and we would need to create
something similar as well for our use case so I will start with this form and
I will copy this form [Music] and I
will come back over here in the
add csst email and to be honest I don't
even have to paste all of it I just I can refer back to this form and just
need the elements you know one by one
so I will start with creating my form
I will create a div first and inside
the div I'll have my
container so div with the class of
container so a class of container
inside the container class I'll have my
form so a form HTML element
and I will remove the action for now
and I will keep the method as post and
I will insert some elements inside
the form but I have to make sure I use
bootstrap classes so for example I will
use this first email label and the
input element so I will copy this
bit over here so this is just a div
with a margin bottom so that the elements can
be separated out between it has a label
it has an input box and it has a help section I don't need the help section so
I can remove this so all we are left is
uh the label and
an input element now let's change this
to uh to work with our form and our ad
model if you remember we have to add a
blog post and for that we need a few
things the first thing according to our
domain model was the ID property but we don't
Supply the ID from the the website the
backend that is Entity framework gives
the ID to us so we would not be taking
the ID value from the user instead let's
start with the heading of the blog post
so I will change the label name to be called heading
and I will delete the form the for the
type of the input element for the
heading would be just a string so it
will be of type text
the class is a bootstrap class so I
will keep it like that the ID I can remove
this or if you want to give the 4 for
the label you can give the ID as heading
[Music] and you can copy the high ID
for the input element back inside the for
attribute and then area described by I
can basically remove it for our examples
[Music] now this is one of the input
element we want to create let's save it and see how
it looks like at the moment if I come
back to uh Firefox into the browser and
refresh this you can see we have a
heading label which accepts The Heading value for the
blog post as an input type of text now
there's no padding or margin between the
form and the uh The Heading we have so
let's add a margin So to that div we have above I will also
add a margin bottom of around two let's
save this and refresh it so we have some
margin but let's add some more so let's
say around five and now it looks better so we have a
separation a good separation between
the form and the H1 tag so let's continue to add more elements
inside here I will basically copy this
div and add more elements one by one the
second element we need or the second uh
item or value we need from the form is
the page title and Page title is
something like if I hover over it it
shows you forms bootstrap version 5.2
and we will have a similar thing for our
blog post as well where we will change
the title of the page or of the blog post we are trying to load
so I will come back and change the
label name to to be called as page title
[Music] and I will also change the ID
and I will paste the ID inside the four
section and this will still be a type of text
now we have two elements on there let's
create the third one which is the
content content will basically hold all
the data
which is text paragraphs like in HTML
and images for our blog and we will use
a text area for that so I will change
this to a text area
so I will create a new text area input
element but I will also
give it a class of form control because
that's a bootstrap class
and this will have an ID property
so ID will be content I will paste the
ID for the label and I
will also change the label to say
content let's save this and review our changes
so going back to Firefox and refresh
the page you can see we have
heading page title and content so let's
carry on and add more elements to our
HTML page the next property we want is
the
short description so for that I will
copy the input type
of text because that will just be a
string maybe of 30 characters or more and I will change the label to be
short description [Music] and I will
change the ID as well
and I will paste the ID for the for
attribute for the label
and the for uh attribute Works in such
a way if I come back and show you
I'll open my website again and if you
click on the heading it automatically
focuses on the input element that the
for or the ID is attached to so if I
open or click the content label it
focuses on the input element
for the content label so next is
[Music]
the featured image URL so I will go
back to my application and that will be a type of string as
well because it just contains a URL to
the featured image and I will have the
label saying that and I will change the
ID
and copy the ID to default attribute of
the label foreign
and after that we will have the URL
handle which will be again a short string so type of text
and the label will be URL handle
I will change the ID [Music] and paste
the ID in the for attribute as
well after that we need three more
properties the first one would be a date field so
when this was published or if the user
can select from a you know you know a
date picker so we need a type of date
over here
and then this will be labeled as
publish date
[Music] I will change the ID
and also paste the ID for the for
attribute after that we need the author so that'll
be of type string so I'm copying the
input type of text pasting that here
and we need to have the author as the
label
I will make changes to the to the ID
and uh the fall attribute as well and
finally we will have the is visible
attribute so we will have we will say is this
visible let's say is visible and for
this one we will have a check
box so we can go back to the bootstrap
website to see how a checkbook works so
just over here on the search you can
easily type checkbox and radio buttons
and this is a
checkbox that we want to use just
without the input element so I will come to check boxes and radio elements
and from here [Music] I want to use uh
I don't want the input element to be
honest so I will just use this as the
form check I don't want the group text
um so I will use this and I'll copy all
of it and come back to my application
and replace it over here
[Music]
and to be honest I think there's
another checkbox that exists so I will search for checkbox again and instead of
the button group or input groups I can
actually just go to checks and radio boxes which are uh you know like a
button over here and and other stuff
and I actually need
something like this with a label and
just the check box over there so this
would serve my purpose really well so I
will copy this div
and come back to my form and instead of
all of this I will paste
this new thing that I copied from the
bootstrap website and it is actually okay not to you know learn everything
that bootstrap has and just use it
directly because there's so many CSS Frameworks out there if you have the
time and the in the capacity to learn
then I would recommend you should surely go ahead and learn but if you don't
and
I mean that's totally fine as well the
documentation is very good and clear and you can totally easily you know just
spare your mind in something very
useful other than you know learning the classes
so you can go ahead and add this and I
will also add a margin bottom of three
[Music] so that I have margin after this
so I
can see this is an input type with a
class from bootstrap type of check box and I haven't given a value of anything
let's wait for you know the next
lecture and we will bind the value of this from
code behind the ID of this one would be
is visible
and let's give this ID to the for
attribute of the label and also change
the label [Music] is visible and we
have the classes for the label so
just with that we have the checks box
ready as well and the final thing we need is a submit button for a form and
we can have that inside another div
with the class of margin bottom of three
and we just need a button and the
button would say save or submit
or let's say submit and then we will
have classes for the
button as well and that will say button
button hyphen primary let's keep the
primary class for now and this will be
type of submit
so that when this button is clicked the
form is submitted
let's go back to our application to see
how it's looking like so I will come
back to my blocky application and
refresh this and you can see we have the heading
title a text area for the content
because we have to parse HTML uh it will
show paragraphs divs images together we
have the short description we have
featured image URL we have the URL
handle we have a date picker as well and
this can be different for different
browsers you know Firefox shows is it in
such a way Chrome has a different uh
look and feel we have the author and
finally we have the check box that is
this block visible currently or you know
do you want to make it visible or hide
it from the users and finally we have a button to submit all of this
information
back to our code behind class and we
will use that to submit it to the
database so finally we have created our
form and
I know this was a big form uh but we
have created it and it is looking pretty uh and in the next lecture we will go
ahead and accept the values coming from
this form inside the code behind class
in this lecture we will learn how to
submit forms and how to read data coming from these forms in our code behind
class there are two ways to submit and
read data and that is either by reading the
incoming request and read values one by
one or to dynamically bind the values to an object
and read from that this technique is
called property binding and this is the
preferred approach but we will have a
look at both of them I will come back to my application and
in my HTML page I want to change a few
things I want to add name attributes to
the input elements so that I can read
it in the code behind class so I will add
name attribute to The Heading [Music]
and then I will add to the title
[Music] I will also give it to the text
area
and basically every other property in
the form so this is for content
then I will have it for the short
description
and because this is just an example
this is not the preferred approach I will I
will stop over here for the names and I
will now show you how we can use the
first approach that we discussed which
is reading the request inside our code behind class
so to do that because we have this form
and it has a method of post so it means
it is binded to the post method of our
class if I go behind the code behind
class and we have an on get method but
we can't seem to find an on post method
so we will create that I will have a
public void
on post method [Music] and whenever the
form is submitted our
values will come over here and this is
the function in which we want to read our values coming from the form so I
will also have a breakpoint over here
and now using the first technique I will
read the request object so I will say
request dot form
so I'm reading the form and then I can
pass inside the brake
brackets I can pass the key name and
that is the name attribute over here so
if I want to read The Heading I can
pass it as a string over here and this will
be the value for my heading input element
so I can store it locally over here or
I can use it in whatever way I want to use
it in a similar way I can also read the
page title
[Music] I can read the content [Music]
and I can also read the short
description [Music]
for demonstration I will read a
property which doesn't have the name field so
I'll just try to use the ID but I know
it will not work [Music]
so I'm giving it a featured image URL
just to show you that this would come
out as a null whereas every other
detail if we pass in from the form will have
some value in it so I'm saving both
these files and starting my application
so our application is running I will go
to the add blog post page and in here I
would provide some values to the form
so let's say this is a heading
this is a page title some content here
and this is a short
description and I'm setting this as
well I am sending value for
featured image even though I know that
this would come out to be null but I
want to prove this to you so after this
I want to press the submit button
and this takes you back to your code
behind class for the add page and it
stops here on our breakpoint on the on
post method now if I continue with this using F10
[Music] I can see the heading value
coming as
this is a heading and that's the same
value that we sent inside our form
after that we have the value for the
page title the content
the short description and we have
nothing for the featured image URL because the request.form
method is unable to bind this with a
key from this form
[Music] so this way we are able to get
all the values from the form and use it to
provide it to Entity framework core so
that it can submit it to the database but this is not our preferred approach
we will use the property binding method
instead which is a much cleaner approach
to submit forms and to read the values
so I will stop my application and
instead of using the properties like
this I want to have public properties
inside my ad model class and let's say I
create a property for the heading first
so I will create a property of type string and that will
hold the heading value from coming from
the input element and the way we want to get the
value or to bind the value from this
input element is using property binding
and we use the attribute bind property
over a property so using this we can
now use the heading
property inside our form using the ASP
helpers
I can now remove this name and instead
use ASP Hyphen for
and now I can use public properties
from this class which is heading
over here like this and that will
create a two-way binding for my heading value
in a similar approach I can also use
the second property or the value which is Page
title and I will say this is Page title
and now I can use the page title
property over here using the same technique ASP hyphen 4.
and I will say is equal to page title
[Music]
after that we can also add similar
properties for all the other forms but
then it will take the entire page and
will look crowded that is not a preferred approach as well but I will
show you how you can do it in a cleaner
way but first of all let me show you if the values are coming back or not so
again I have my input element and I
will start my application
I will navigate back to the admin ad
blog paste page and I will enter the value this is a
heading and this is a page title I will
submit the form
and because I have a breakpoint I can
now hover over these public properties and as you can see their value is coming
from the form and Page title also comes
out to be this is a page title
[Music] so now we found a way for which
I can
read the data coming back from our form
back inside our code behind class but
you would ask a question that you know
do I have to create all these properties one after the other well the answer is
no you can create a single object over
here like an add blog post model and
then you can have properties inside of
that model and that will be way cleaner so let me do that let me stop the
application and I will create a view
model for this so inside the models folder I will
create another folder alongside the
domain so I will say right click add a
new folder and I will call this view
models
and inside this view models folder I
will create a new folder so add a new
class sorry not a folder and I will
name the class add blog post
and the properties of this model class
will be similar to what we have in the
domain model so I will open the blog
post domain model and I can basically save some time
copy everything and paste it inside my
ad blog post model
but I don't want the ID coming from the
form so I can remove this one so all other properties I want the user
to fill in from the form and hence I
have all the other properties except for the ID
I can close this ad block and now
instead of these two fields
I can create a property with the type
of this view model so
it'll be add blog post view model and I
will import
this using control Dot and this is
coming from The View models folder
I will name this add blog post request
because it's a request or a response
coming back from the form and finally
I have to use the bind property
attribute over this property so that I
can bind it back inside my HTML form so
I'll come back over here and now it's
showing me a red because the property
heading doesn't exist but now we can use the add blog request dot heading
to bind the heading to the element over
here and in a similar approach I will
use this Dot page title and I will copy
this for the other
elements as well so I'll remove the
name field ASP for this is content so I will
change this to a content after that we
have the short description
so I will change this to short
description [Music]
after that we have the featured image
so we have the property binding for
Featured image then we have URL handle
[Music]
then we have published date [Music]
after that we have two other properties
one for the author and the last one is
the input element
for the is visible property [Music]
and that's it so finally we have a form
that is that we are able to submit from our Razer
page back to our CS class and we are
able to read all the values inside the
onpost method so in the next lecture we
will go ahead and use the DB context
class so that we can call Entity
framework and persist our data inside the SQL database
we have built a form which we are able
to submit and send values back to our
code behind class in this lecture we
will use this data and save it to the database with the
help of Entity Framework we will use
the DB context class to talk
to the database using Entity framework
so let's see this in action
we are back to visual studio and we
have to write some code in the on post method
because our eraser page when we submit
our form it posts data to the on post
method so we have to write some code
that we can use the DB context file if
you remember the slides it will talk to
Entity framework core and save the changes to the database and we can use
bloggy DB context by using the services
so if you remember in the program.cs
file we had injected our DB context
which is our blog EDB context inside
this services collection of our
application so we can easily call the DB
context and our application will take
care of the instances and will provide
us a proper instance of blog ADB
context which we can use and persist data inside
our database so to use this we will
come back to the
add cshtml.cs class and in here we have
to create a
Constructor because we will be using
Constructor injection and we will inject our blocky dbcon stack context inside
the Constructor and to create a
Constructor the shortcut is c t o r for
Constructor and then you have to press
tab twice and this is our Constructor for this
class now you can inject the bloggy DB
context as a parameter to this Constructor so I will say bloggy
DB context and to import this from the
from the
data folder I will press Ctrl dot or
control period and then I will use this
statement now I have to give it a name
so I can use the name that Visual Studio is
suggesting me and then I have to create
a private variable of this class over here
somewhere so that I can use this within
the class and there's a shortcut to that as well so if I click on this variable
name I can press Ctrl dot again and I
can use this extension create and
assign field with this name so it has
created me a private read-only
variable of type blocky DB context and
I have a name as well Some people prefer a
different naming convention for example
with underscores so I can you can change this and you can also change this to
underscore and that is totally fine as
well it is totally up to you of which naming convention you want to follow but
I will just keep the one which Visual
Studio provides me so now we have a private variable which
we can use inside the on get or the on
post method
so let's use this I will use the
private variable inside my own post and I have
to call the table because I have to
talk to the table the blog posts table to add
a new blog post and if you remember we
have inside the bloggy DB context a
property set called blog posts which is
kind of a table it maps to a table
inside SQL Server so I have to talk to
this table and use a method called add
to add a new blog post so let's come
back to the code behind class and try to
access this table which was blog posts
and this is our DB set
and this DB set or the table will have
a method called add which Entity framework
code gives us so we can use this add
method and to this add method we can provide a
new domain model of blog post so we
have this domain model over here
which is blog post so we can give it a
new object or an entity or a domain model called blog post
but we don't have a blog post at this
moment we only have the add blog post request which is a different but it has
similar properties so we'll have to do
a mapping from this model to the blog post
domain model and then Supply that to
the add method so let's create a new domain model blog
post so I will say a variable blog post
is equal to new
blog post and I will press control dot
to bring in the dependencies [Music]
and I will use that from the domain
models [Music]
and now I have to assign all these
properties one by one so you can follow
the order in which they exist so that
you don't miss anything I don't have the ID coming from the form so I will not
assign the ID but I will start from the
heading so I can say heading is coming
from this request dot heading
and then we have the content most
likely so we have the page title then the
content so I will say page title is
coming from this request Dot Page title
then we have the content
after that we have the short
description
let's see what else we have we have the
featured image URL handle and publish
date so I can say featured image
and visual studio also suggests you
that it must be coming from from this object depending on how you have
structured it
so you can use the tab to actually fill
in the details really quickly so I'll say uh the URL handle and look at Visual
Studio suggesting me in Gray so I can
press the tab button to just auto complete it for me
[Music] and
after that we have the uh the pending
things we have the published date which
is coming from this dot publish date
then we have the author coming from the
request again and finally the visible
property coming from this dot visible
now we are only left with one property
which is the ID but I don't want to assign the ID because the bloggy DB
context when we are trying to add it to
the database will automatically assign me a new guide so I don't want to do
that so we have a an object of type
blog post
so I can use this object and pass it to
the add method over here
[Music] like this and I can close the
statement
now we have told the context that we
want to add this blog post to the DB set
blog posts but now we have to call the
context again to save the changes so I
will call bloggy DB context and use the
method save changes so this line is very
important because if you don't write
this line it won't save the changes to the database and you won't be able to
see any new blog posts in your table
[Music] so with all these changes I am ready to
start my application and test this
really quickly our application is running so I will
navigate to the add blog post page and
we have a form ready so I will fill
in the form really quickly before
filling the form one thing I
noticed is we for the is visible
attribute we also have the value coming
in from the form which is unnecessary
and will impact in how we save the changes so I will come back and make
just one more change I will come back
to the ad.cshtml and in here I will scroll down to the is
visible element and we have [Music]
the value property for this one over
here so I will go ahead and remove this
because we are binding the value for
the check box from this binding property
over here so we don't need the value
property so I will remove that and save changes and start my application again
so I've come back to my application and
I filled in the form so I've given it a
heading a title a Content which can be
in HTML as well because we'll have to show a text and you know images as well
inside our blog post this is my short
description this is a stock image
picture that I took from the internet
and later on we will convert this to you know an upload functionality as well
this is My URL handle and it basically
acts as a URL to the blog post so that's why I
have you know separated this with
hyphens so that it is also SEO friendly search engine friendly
I have put in today's date as the
published date and I've mentioned my name as the author and I've also
selected the is visible property so if
I submit this it should come back to my code behind class and now it's doing
the
mapping so let's see if the mapping
works I have all the values coming in here for
the domain model and after that bloggy
DB context is adding this to the database and finally
saving this so let's come here I'll
press continue
and there's nothing to show there's no
success message at the moment to show but we will work on that in future so
with that I can go to the database and
we had none records before so I will
select this again and we have this new
blog post that we added from the form is now reflecting
back inside a database so using the
bloggy DB context and Entity framework code we were able to persist our changes
back inside the database and we have
all the values for all the individual Fields
coming back over here as well [Music]
in this lecture we will read the records
that we saved in the database and show
the list of all the blog posts in a nice bootstrap table
for that we will come back to our code
and I will first stop my application
for this to happen I have to create a
new Razer page inside the the blogs
folder of the admin and we had the add
page before so now we need a page where
we can show the list of all the blog
posts so I will create a page called list so that we can show all the blog
posts so I will come to this folder and
I will right click to add a new Razer
page I will select the empty template
and click on ADD
I will give it a name of list
and now we have a new web page a new
Razer page with the name list in it
as we have seen before the list eraser
page also has a code behind so if you press F7 or you can navigate from here
if you press F7 it toggles between the
Razer page and the code behind class it
has the ongate method and this is what
we need as well so we want to load the
records that we saved in the database
inside the on get method or when the
page loads so this is the method that
gets hit when the page of the list page
loads so we will have to call the
database here and we know how we do that
we use the bloggy DB context and first
we have to inject this so we will create
a Constructor [Music] so I will start
type ctor and then press
tab twice and inside here I will use
Constructor injection and pass the block ETB context
as a parameter just as we did in the
ad.cshtml functionality so I will say
bloggy DB context press Ctrl dot or
control period to get
this from the data folder give it a
name and then press Ctrl dot
to create an assign field a private
field called bloggy DB context
and now we can use this private field
inside our on go on get method
I will save this so I will use the
context and try to
access the blog posts table and you
know blog posts is a DB set property of
context so I can say dot blog posts so
we are trying to access the blog
posts table and then getting a list
from there so I can say dot to list
because we want to get all the items
that are stored inside the blog posts
and now it's time to show this on the
Razer page of the list page so I can
store this into a variable
I have given it a name of blog posts
signifying all the blog posts you can say blog post list
and I have to create a public property
so that I can show this uh all the blog
posts inside the HTML so I will create
a public property and you know the shortcut prop double tab
and this will be a list of the domain
model blog posts so I will say
a list of blog post
and press Ctrl dot to get this from the
domain model and I will name this
blog posts so I can use this public
property and
assign the value of what is coming from
our database so instead of look storing
it in a local variable I can use this
and store it inside the public variable over here
so now if everything will run fine our
blog post variable will have some data
in it so we can use it inside our HTML
so going back to the HTML now we need to
have an HTML structure so that we can
show the list that we should want to show inside here and we will follow the
same Convention as we used in the ad
cshtml so I will copy the first div
because it is the heading I will paste
that here and I will change
the heading the H1 tag to show to or to
say uh blog posts
you can say all blog posts or blog post
list or anything like that and after that I have a container so
I'll just use it on my own so I'll
create another div
with the class of container and inside
the container I want to
create a bootstrap table so I will
create a table element and I will give it a class of table as
well because that's the bootstrap class
we want after that I can remove this TR because
I want to create the T head first which
signifies the heading for the table so T
head in the T head we will have just
one row
so one TR and one TR will have a few
columns so TDS
the first TD will hold the ID then we
will have the heading
and you didn't want to show everything
in here because the user should be able to click on one of these and then
navigate to another page to see all the
details so I will have limited information here the heading and the ID
looks to be okay and if we need more
information we'll just put it later on
then along with the T head we will have
the T body
and the T body needs to contain all the
list of blog posts that are stored in
the database so we need some kind of a
for each Loop in here so
I will create a for each Loop using an
add symbol as you know this is our razor page and
we can write C sharp over here as well
so using the add symbol I'm writing the for each Loop
The Collection that we want to iterate
on is the public property here so I can
say [Music] model Dot
blog posts so that's our public
property and I will change the name of this item
to say it's a single blog post so blog
post after that I need to create all the rows
so I will create I can copy this TR Str
structure and paste it over here so we will create
TRS for as many items we have as in the
database and the TD will be coming from blog post
over here so first is the ID use the ad
symbol again blog post Dot ID
and then we have the heading so again
blog post Dot
heading and save these changes so this
looks good it's now time to test
if we are able to pull back all the
results and able to show it in the bootstrap table or not so I will run my
application I don't have a way to
navigate directly
to the to the list of blog posts so I
will just use the browsers URL over here
so I will navigate to forward slash
admin forward slash blogs
forward slash list if you remember we
created a razor page using this keyword
and if I enter that it is trying to
load this web page and you can see there's uh
the heading for our table and it's
pulling back the values coming from the database so if I show you the database
we have just one entry in the database
and hence it is only showing you one row
inside the table we can add the link to
this page inside
our drop down navigation over here so
let's come back to our application
and let's open the layout page and
inside the header where we have this
drop down we only have one list item so
along with that I would copy and paste
it one more time this is a drop down
item but it goes to admin slash blogs forward slash list
so I will change it to list and also
say let's say view all blog posts or you can
say uh blog posts or anything that you
like
we have saved that and the hot reload
has worked so coming back if I refresh
this we should see two links and one of
them goes to this link over here
so we are able to successfully show the
list of blogs on our page let's do
another thing we if we are submitting
our form and if it is successful we
should be able to navigate back to our
list page showing that it was a successful results so let's do that
quickly for that let's come back to our
code and inside our ad
cshtml.code behind class we will come
over here and change the type of this on
post method from void to I action
result so that we can return something from
here and we want to redirect to a
different page right we want to redirect to a list page
so we will write return redirect to
page
and then in strings if you go here we
have an overload method where it takes
this page name as a string and the page
name for our list page is coming from
admin blogs list so we will provide
that with a forward slash admin
forward slash blogs forward slash list
and we will close the statement
and with that change I will run my
application again
I will go to admin and I will go to the
add blog post page
I will fill in some details here just a
really quick one
and when I submit this it comes here to
the breakpoint I can now remove the breakpoint and continue
on this so it's saving the changes to
the database and it has redirected back to
the list page upon a successful save so
we have two items now in the blog post
and if you see the database we now have
two items here in the database as well
[Music] in the last lecture we saw how
we can
list or read all the records from the
database and show them in a nice bootstrap table in this one we are going
to edit or update these records one by
one and for that we have to navigate to
another page so we want a view button
over here or an edit button that takes us to another page which shows us all
the information that we can edit and
then using a submit button we should be able to update the details in the
database so let's work on that let's
first create another button over here which is like a view button so I will
come back to my code I will stop my
application
and I will add a button to my list
class over here so I'll go to the Razer Page
by pressing F7 and in here we only have
two columns so
I will add another column for the
heading I will just keep it as a space
and for the actual column which is
showing all the records we will have an
anchor element so I will create an
anchor element and the value of this anchor element
will be just saying View and then we
will have an href to this
but what does the href be so for that
as we said that using this
button the user will be able to
navigate to another page so that they can see the details and update them
accordingly so
we need to create another razor page as
part of our Cloud operations and that will be inside blogs as well and we will
call it edit so I will right click on
blog add a new razor page
and I will use the empty template click
on ADD
and I will name this one edit and click
add
so we have this new edit page over here
now we have to read the information
based on the ID coming from the list
over here which is this one inside the
edit page so let's do one thing let's
give the href to this view button so
that it takes this particular blog post
into the edit page so for that we will
use forward slash admin because we know
what the location of the URL will be
forward slash blogs and then forward
slash edit
and then we need one more information
and that will be the ID of this blog post because that is important we will
use this ID field to query the database
again and get all the results for this
ID so using the route parameter I will
use the add symbol and say ID
and it's coming from the blog post so I
will use blog post dot ID
so this way because we are using a for
each Loop the anchor element will have the ID for that particular row and
nothing else now we are passing this ID
inside the
URL but we also have to read it inside
the edit page so that we can further use
it so I will go to the code behind
class and we need to read the ID over here so
I will say the on get method uses a
good and the name of the quid is ID and it
has to be the same name as we will
Define in the razor page so we will come back to the Razer page and where the
top
says add page we will accept a route
parameter using a string and then in
curly braces we will mention the name
of the route parameter that will be ID
and to constraint it or to make it type
safe we will use the colon and then also
mention the type of this ID we know
that IDs in our application are of type Goods
so I will mention good [Music] you have
to make sure that the name of
the route parameter that you are using
in your page matches the parameter that
you are giving inside the ongate method
so that it is able to map it correctly
now we have the ID coming inside the on
get method we can make use of the blocky
DB context and Entity framework core to
query the database using this ID so we
can inject the DB context inside our
class using the Constructor injection so
let's create a Constructor first so
ctor double tab and now we can inject the
blog ADB context as a parameter
press Ctrl dot to import this
and then give it a name and then press
Ctrl dot again to create and assign this
private field over here which we can
use inside the ongate method
so I will use the blocky DB context I
will access the blog posts DB set or
the blog posts table and then I will
use the find attribute or we have a few
other ways to do it as well you can use
the first or default as well and you can also use the find attribute because it
it uses the primary key of the table to
search in the database and the primary
key for our blog post table is the ID
which we know so let's use the find
and pass the ID to it using the
statement it will give us a
result and it could be a blog or it
could be null because the ID was incorrect so let's store it in a
variable first so variable blog post is
coming from the
database and now we will check if blog
post
is not equal to null that means we have
to show it inside our
our razor page so we will show that
otherwise you can send them you can show
them a 404 or something like that but
we will just create a public property first and then show it inside our Razer
page
so for that I need a public property so
p r o p and then it is a single blog
post so I will say blog post
press control Dot and it's coming from
the domain models but if we show it from the domain models it will have to be
uh
you know uh coming it it will also take
the ID as well so I'll I'll use this
and I will call this blog post [Music]
and let's just assign it directly
and let's worry about the you know
showing the 404 later on as well so this could be null as well that's why
we are having the squiggly over here so
we have the public property blog post
which is having the information of the
blog or it could be empty as well so now
it's time to show this information
inside the Razer page so I'll come over here
and our edit page will look a lot
similar like our ad page if you if you
can imagine that so we'll show all the
properties and we have all the properties inside our ad page so I will
use some of the properties from this
razor page so I'll copy all of it and
then change it according to my need so
I'll copy it and come back to my edit
eraser page paste it let's first change
the H1 tag the heading to say this is edit blog
post after that we want to show the ID
but we were not showing the ID for the add page
so let's add another field on the top
just after the form
and we can say the ID is ID
and the label for this is ID this is an
input type of text
and this is for we have to mention the
public property we have but we don't
have the bind property attribute that's
why it's not showing it over here let's make it a two-way binding so let's come
back to my code behind class by
pressing F7 and let's make this public field
with the attribute of bind property so
that whenever the form is submitted later on we will also get the new values
inside this blog post let's come back
to the Eraser page and
now we can use the blog post public
property and this is the ID field so I'll change
it to ID and for all these red
squiggies that you show here we just have to use the public
property and replace it with this
so I'm doing a quick search and replace
over here
so that all of it is coming from the
public property that I have
so this looks fine and we have gotten
ridden of the errors and if I save it it
is now time to to see what it is
looking like I'll make one more change for the
ID we don't want to the user to change
the ID so we will make it a read-only
field and save that as well so now let's
run our application
[Music] the application is running and
let's navigate to the blog posts which is the
list of blog posts and you can see this
new view anchor element over here and if I hover over it
you can see on the left hand side
bottom it goes to slash air admin forward slash
blogs forward slash edit and then we
have the ID inside the route and the ID
matches the ID for this row over here
so if I press the view button I should be
able to see the details for this blog
and it goes inside to the edit page as
you can see in the URL and it has the
ID as well inside the route so this is our
route and it has gone back to the
database to fetch all the details for this
particular ID which is read only so the
user can't change it and then we have all the information populated in here
just because it was the same
information let's open the first blog just to make sure if we are having
different
information being populated and you can
see it's it's looking perfect
so we have the information showing on
this edit page but our button doesn't work at the moment because we don't have
an on post method so we have to
implement that functionality
for that let's go back to our code
and let's stop our application I will
go to the code behind class for
this edit file using F7 and we only
have the on get method over
here so I will first create an on post
method so public
void on post and then this on post
method will make
use of this public property which is
also binded to the form so the values
coming from the form that the user
wants to change are also coming over here I
will make use of this and I will also
query the database so that I can update the database using the bloggy DB
context
so let's do that let's first query the
database again so I'll use the same
query in here now the ID doesn't come
from the parameter
but it comes from the blog post so I
can say blog post dot ID
it tries to go to the database and find
this blog post for me so I will change this to be a variable and say existing
blog post [Music] now we have an
existing blog post and we
have a blog post coming from the form
that we submitted so now we have to
change the values of the existing blog
post to the values coming from the form so we will say if
existing blog post is not equal to null
then we have to change the fields that
we want to change not the ID but
everything else so the heading is coming from the blog post dot heading
and after that we have similar
properties so let's say page title
[Music] is coming from blog post Dot
Page title we have the content
and then we have the short description
[Music]
and then we have a few other fields so
let's go back to the blog post domain
model so we have featured image URL so
let's do that
[Music] paste it then we have the URL
handle
[Music] after that we have published
date author
and visible so we have published date
[Music]
we have the author [Music]
and we have the visible property also
make sure that you are not missing
a property over here and you can again
follow the same rule or advice that you
can keep these in order so that you
don't miss a property after we have updated the existing blog
post it is now time to save our changes
because bloggy DB context and Entity
framework is already tracking this so
we don't have to use an update statement we just have to save the changes so
using
the bloggy DB context we will use the
save I'm sorry using the blogging DB context
we will use the save changes method to
save our changes to the database and
with that we can also redirect this
back to the list page upon successful update
so I will change the method from void
to iaction result
and down at the bottom after the
success of this I will return
redirect to page [Music] and I will use
a string to navigate to
the list page so forward slash admin
forward slash blogs forward slash list
and close the statement so now our
functionality for the edit button is
done as well let's test it I will start
my application
let's navigate to the blog posts page
and let's change this blog post over
here so I'll click on view
and I will change a few properties
let's say this is another heading
this is another page title and you can
make some more changes over
here somewhere just to test it out and
I will you know turn off the visible
property and I will change the name to
my name so I will submit these changes
and hopefully our blogging DB context
will save the changes back to the database so I'll submit it and it has
correctly navigated back to our list
page upon a successful update so let's see and let's confirm if this was
successful we have the headings now the
ones that we updated and all the other details as well and even the check box
and to double confirm it we can come
back and execute our table again and as
you can see the second record now has
the updated or edited fields [Music]
so our edit functionality or the update
functionality as part of our crud works
in the next lecture we will go ahead
and work on the delete functionality
we have made great progress as part of
our Cloud operations and we have implemented the create read and update
part of that functionality it's now
time to implement the delete functionality
and for that we will have a button
inside the edit blog post page somewhere
around here and we will use that button
to delete this blog post if the admin
wants to so let's go back to the code
first
and I'll stop my application in the
edit page I first want to show
another button which submits the form
or which takes you to the code behind so
that I can make use of the bloggy DB
context to delete the blog post from the
database so as part of this div class I
only have one button but I will create
another button and I will give this a
class of button
and button Danger that's a bootstrap
class which gives you a red color button and that will signify
that this could be used as a delete
functionality the type of this button is submit
so type is equal to submit and then the
name of this button would
say delete so I will have delete button
over here now to separate these two buttons we can
have this button right to the end so I
will give this div a class of deflex
that means I want to display this as a
flex and then I want to have the justify
content between so that I have space
between these two buttons and they are
arranged well on either sides of that
row [Music]
we have added the button and it Summits
the same form that we have over here
and if we look at the code behind by
pressing F7 it goes to this on post
method over here so how will our button
uh recognize which what functionality to
implement whether to implement the
update functionality or whether to implement the delete functionality
because we are using the same form so
razor Pages gives us a very nice way
wherein we can create page handlers and
we can tell the button that when you are
clicked and you are submitting the form
please go to this handle or this action
method so I will first change this
existing method and give it
a page Handler and I will also
Implement that in the button over here so I am on
the edit CS HTML and I will first
change the existing submit button I will add an
asp for attribute sorry ASP page
Handler attribute
and the value of this page Handler
attribute would be let's say edit
or you can say update but you have to
give the same name so I will copy this
name and I will go back to the code
behind and now I will change my method
name to say on post edit and this edit
text over here or the value will act as
a page Handler so when this submit
button is clicked inside the Razer page
with the ASP page Handler as edit it
will go to this method over here with
the word edit in it [Music] now that we
have taken care of the
existing button it's now time to also
give a page Handler to the delete button so I will have the ASP page Handler
attribute and the value for that one as
your right is delete
so we will have to create an on post
method for the delete page Handler so I
will come back to my CS class and I
will create another on post method so I will say public
I action result on post and on post
keyword in the action name
tells dotnet and Razer pages that this
is a post method otherwise you can also
annotate this method with the HTTP post
attribute over here like this
so I will have the on post method and
then I will also have the page Handler name
that is delete which matches the button
over here
and now we know that the on post method
delete will come to this method when the
button is clicked so as we were doing
before we want to get the ID and we want to first check
the database if this blog post exists
and if it does we want to delete that
blog post so let's search the ID first
and we will use the same query
we will say variable existing blog is
equal to we will use
blocky DB context to go to the blog
posts DB set and find the unique
identifier and that's coming from the
form which we can access through this property so I will say blog post dot ID
[Music] after that we have to check if
the blog exists so if
existing blog is not equal to null then
we have to remove the block so we
have to call DB context again use the
DB set property so blog posts and then use
the remove method and then the remove
method takes the domain object completely so we can use
this domain object if it was found then
please remove it and finally let's not forget to call
Save changes so blog a DB context dot
save changes
now after a successful uh successful
deletion we want the user to be
redirected back to the list of pages so
we will use the same return statement as we did before so return
redirect to page [Music]
and then in strings we will pass the
name of the page we want to redirect to and that's forward slash admin forward
slash blogs forward slash list I will
close the statement and I also
want to return this to somewhere if
this was not found and we will Implement that
later on but I can just return the view
for now but later on uh so I return the page but
later on we will make sure we show some
kind of a message on the screen telling
the user that this user or this blog
post was not found so save those changes and it is now time
to test our changes so I will start the
application
our application is running so I will
navigate to the list of blog posts
and let's choose this one the second
one it is showing me the details now let's
also test our edit button if it still
works because we made changes to it so I will update the author name and
put my full name in here and submit the
value
takes me back to the list page meaning
that it was successful let's confirm that
so my full name is showing now so the
edit functionality still works and now
it's time to use the delete
functionality that we've implemented so I will click on this delete button
and it takes me back to the list page
and you can see there's no element now
or no blog post with that ID
so we have successfully implemented our
credit operations that is create read update and delete
in the next few lectures we will go
ahead and enhance our experience using
these Cloud operations so we will do
some more advanced level stuff like asynchronous programming and we will
also create a repository so that we can
we don't have to directly call the the DB context from the page rather we will
call the repository and the repository
we'll call the DB context all of that in
the next few lectures in this lecture
we will use the power of
asynchronous programming and make our
methods asynchronous you probably already read about
asynchronous programming async and
await keywords are used everywhere no matter
which programming language we choose
talking about the dotted framework and c-sharp in particular we have some
native functions classes and reserved
keywords that we can use to implement asynchronous tasks and workflows in our
project we could Define asynchronous
programming as the way of executing programming code
in a thread without having to wait for
an input output bound or CPU bound tasks
to finish input output bound operations
could be a file system access HTTP
requests API calls or database queries
So based on this let's go ahead and make
changes to our code to make our methods
asynchronous I am back to my code and I have to
change the methods that we created
inside the pages folder and we worked on
the admin section inside blogs and we
have these three classes that we created
and we have to make these one by one
asynchronous so that we can you know
have the power of asynchronous
programming so I'll first start with the
add plus so I will open the code behind
class for the add file and in here we have this method on post
and we are trying to make database
calls so if you remember the definition if you
are making database calls it's probably
a good thing to make use of asynchronous programming and Entity framework core
helps us achieve that so in order to
change this to a async method we will
first start with the definition of the
method and we will make this asynchronous by adding the keyword async
now I have to wrap this I action result
inside a task
so this becomes a task of type I action
result after that we have to change the uh the
way we are calling bloggy DB context we
have this add method but Entity
framework core also provides us the
asynchronous method in case you want to use it and in our case we will use it
so
we have another method called add async
so if you start typing add
async we have this method so we will
use that if you are not seeing this method please press Ctrl Dot and pull in
the
dependencies over here now because we
are using the async
method it is suggesting us that we use
the await keyword because this call is
not awaited execution of the current
method continues before the call is completed so we have to use the await
keyword [Music] and the next line is
also from the DB
context so we have another method
called save changes async so we will change our
method instead of save changes we will
use Save changes async and because we
are using the async method we can use
the await keyword here as well [Music]
so with these two changes we can save it
and now our add function should work as
is we will test all our functionality
once we have made changes to all our files so
let's go to the edit class now and
let's open the edit cshtml.cs file here we have two methods
the on get and the AUST on post methods
let's first start with the on get method
we are making a call to the database so
this method also needs to be asynchronous so let's change the
structure first let's make it
asynchronous and because this was returning a void
before let's make it just a task now we
can use another method which
Entity framework core gives us which is
find async so I'll use find async
instead of find and because we are
using the async method we have to use the
await keyword over here now it suggests
me that there could be a
possible null reference assignment so
in our HTML we will
check if this is not null and if it is
then we'll just show a message so we'll
come back to the edit page over here
and we have to wrap this segment inside
an if statement so I'll first start the
if statement and I can use the add symbol to write my C sharp code I will
say if model Dot blog post is not equal
to null
that means it has some value I will
open the brackets [Music]
and then I will place my my section the
div which shows all the elements inside
this if statement so I have cut it and
pasted it inside the if statement
if my blog post was returned as a null
from the database then I will use an
else statement and in here I will have
a div [Music]
with a class of container and then
inside that I will have a
paragraph and I will say blog post not
found
or you can have a different message so
with that change we now have our
on get method as asynchronous and using
the fine async method we are able to
return that blog post back to our razor
page now we have made the on get method as
asynchronous it's now time to make the
on post methods which are edit and
delete asynchronous as well we will start
with the edit method first
I will change the structure I will add
the async keyword and wrap the I action
result inside a task and now I have to
change the usings of
the bloggy DB context I know I have a
find async method so I will use that instead
and because we are using the async
method I can use the await keyword over here
[Music] after that we are mapping this
inside our existing blog post so that's fine
and finally we save the changes so we
can call the save changes async method
as well so let's call Save changes
async and a weight on it
and finally if everything was
successful it returns back to the list page
now we have to change the on post
delete method so again the same Theory we have
to change the structure to async and
wrap this inside a task
[Music] then we were finding the blog
post in the database so use the async keyword
and await on it [Music] after that we
don't have any method for
the remove so remove stays the same you
can check it but remove doesn't have an asynchronous method but finally we will
have the save changes async over here
and because we are using the async
method we will use the await keyword
and upon a successful delete we will
return back to the list page [Music]
now we have changed two pages the final
page is the list page so I will open
the list.cshtml.cs file
in here we are using the ongate method
to retrieve all the list so let's change
this as well use the async keyword and
instead of avoid let's use a task instead
then we can have the extension to list
async which also Entity framework code
provides us so using to list async as
you can see it is not available to us
by default so I will click over here
and press Ctrl dot or control period And I
will import this using statement so I
have imported using Microsoft dot
Entity framework core to use this
method and then I can convert this or I can use
the await keyword because this is an
async method now I have to go to the Razer file
and wrap all of this inside an if
statement because otherwise we won't be
able to see any results so I will say
if [Music] model dot blog posts is not equal to
null then show me the details of it
[Music] so I will delete everything
from here and cut paste everything inside the if
block and I will also have an else
statement which will say which will have a div
[Music] and that will have a class of
container
and again I can have a paragraph inside
it which says no blog posts were found
and again you can have a different
message so if the blog posts were found I will
display them in the table otherwise I
will show this message so let's run our application now because
we have finished making all our methods
asynchronous Let's test this and I will run my application
[Music] the application is running
let's navigate to the list of blogs
[Music] we are able to see the list of
blogs as
before and now let's open the view
button we are able to see a single block
details so all of the details are here
let's change this
to see if the edit functionality still
works let's submit that and it returns back to the list page
the records were updated fine as well
so that means the edit functionality also works fine let's try the delete
functionality and it comes back over
here which means the delete functionality also works
let's see if we are able to see that
message again that if there are no blogs we should see the no blogs found
message
so I will delete this blog as well
and we don't see that message because
we not have the blog posts as null we are
having that as an empty list so you can
say here if they are not null and
if this contains any so model dot blog
posts dot count or you can say dot any
[Music] then show this list otherwise
show this message so I will hot reload my
application and refresh this
now you see that we have the message no
blog posts were found because there were
zero blog posts before this makes our
application asynchronous
and moving forward we will be only
using asynchronous methods and in our
application in this lecture we will
understand the repository pattern and we will Implement
that in our application this repository
design pattern in c-sharp mediates between the domain and
the data mapping layers using a
collection like interface for accessing the domain objects in other words we
can
say that repository design pattern acts
as a middleman or the middle layer
between the rest of the application and
the data access logic
that means a repository pattern
isolates all the data access code from the rest of the application the
advantage of
doing that is that if you need to make
any changes all of those changes are in
one place now so you just have to make
changes to the repositories that you have and then all
the controllers or web pages that
implements these repositories will just
remain the same so let's go back to our
code and create some repositories and
also Implement those report
repositories inside our web pages the process of creating repositories and
using them is very simple first you
have to create an interface for the repository then you have to implement
that after that we will inject them
inside our program.cs file inside the
services collection and then we can use
it wherever so let's first start with
the interfaces I will create a project
or a folder outside the pages so inside
my web application I will right click
add a new folder and I will call this
repositories [Music]
inside these repositories folder I will
have interfaces for my repositories so
the first interface I want to create is
for the blog post model and I want to
you know do operations to the blog post
DB set or the table so I will first
create an interface for that so I will
right click on the repositories and add
a new class and I will change this to
an interface so you can select interface
and let's name this interface now so I
will call this I just to donate that
this is an interface so I will call
this I blog post Repository
and I will add this so I have a public
interface I blog post
repository now I need some methods here
and if you know what interfaces are we
need to create some definitions of the
methods that we want to implement inside classes so the methods here would be
something like like get all the blog
posts get a single blog post you would
like to delete a blog post and update
it as well so we will Implement all those
methods in here one by one so we will
first start with getting all the blog
posts and I know we have already done
the implementation but now we have to implement them using the repository
pattern so I will first create a
definition so I will first start with the
definition of the all blog posts so I
will say task
and that will be of type I enumerable
or I can say a list and that will be of
type domain model which is blog post
and I will say control dot to get this
from the domain models and I will name
this method get all async [Music] so
this is the get all async method for
the blog post repository using this
method I am getting all the blog posts
stored inside the database so this is
just the definition we will soon create the implementation and we
already have a lot of code for it
inside our pages so we will reuse a lot of that
the next method would be to get a
single blog post so I will create another definition and that will be task of
type
single blog post so just a blog post
and that will be get async and I will
get this using the unique
identifier and that is ID and that is
of type good
and I will give it the ID name [Music]
so using this method we should be able
to get a single block post from the
database using the unique identifier
after that we need to create three
other methods one is for update the second one
will be delete and the third one will
be add so let's start with the ad first so
for the ad I will return a single blog
post because
I'm adding a single blog post so I will
return this later on whenever this is successfully added I will name
this method add async and this would
accept the blog post as
in the domain model so I can write post
as a name or blog post
[Music] after that we have two other
method spending so one is the update and
similar to the above we will have task
of type blog post
then we will have the update async
method as the name and after that the parameter of that
would be blog post [Music] and finally
we have the delete method so
that will be a task and you can have a
Boolean type or anything else so let's
keep it as a Boolean which is a return
type and the name would be delete async
and this takes a unique identifier as
well because it just needs the ID of the
blog post to delete so that will be of
type quit and the name is ID
so we have all the definitions now
ready inside our interface it's now time to
create a class which will act as an
implementation of this interface so let's create that inside the
repositories folder right click add a
new class
and I will call this blog post
Repository
and this will act as an implementation
of the interface so we have to inherit the interface and that's I blog post
repository so add that and you
immediately see a red squiggly over here
telling me that we have some errors
because we haven't we are implementing
this interface but we haven't
implemented all the methods inside this interface because that's a must so
let's
use the shortcut I will control dot
over here on this
repository name and I will use this Implement
interface and get the structures for all the
methods that I had created as a
definition inside the interface
so now now let's go ahead and Implement
them one by one
I will first start with the add
functionality and if you remember we have created the
add functionality already so let's go
back to the code inside pages
admin blogs and then let's go to the
code behind class of the add page
[Music] on the on post method we have
these two lines that are
typically saving our changes to the
database using the blogging DB context
and we have this blocky DB context
because we were injecting that inside the Constructor
so we'll come back and create a
Constructor inside our blog post
Repository so that we can make use of
the DB context and if later on we want to
replace that DB context we will just
have to work inside repositories and no
other web page and that's the power of
using repositories
so I will say ctor to create my Constructor
and using Constructor injection I will
inject the bloggy DB context [Music]
press Ctrl Dot
and using the data folder I will import
it then I will create a name for it
and then press Ctrl dot again to create
and assign this field
so now we have a private read-only
field bloggy DB context which we can use
inside all of these methods to talk to
our database
now we can use the blog ADB context
inside the add method over here so I can
remove the throw new non-implemented
exception I can take that away and then
using what we did before I can come
back to the post method and
copy these two lines over here because
that's what we were doing to
save our blog post so I will copy that
and paste it over here
so we are taking a blog post we are
adding it to the database and then we
are saving changes and because this is
an asynchronous operation we have to use
the async keyword over here and that
solves all the red errors and
that's that's gone away after the save
changes Entity framework core has given us a unique identifier
for this blog post so we can return
this blog post from the interface or the repository
back to whoever is calling us and in
this case we will call this repository method from the add page but that's for
a later video in a similar fashion we
will go ahead and update the other functions so let's
start with the get all method and I can
remove this line and implement
the get all operation I will start by
making this an asynchronous function
then I can use the bloggy DB context or
we have already done this before so I
can go back to the list page in the Cs
file and I can use this method over here
copy that and then come back to my
repository to paste it
now we are getting the list from here
the list async method doesn't exist so I
need to do a control dot over here and
import this using statement
so I have using Microsoft dot Entity
framework core and that way I can use
the tool list async method finally
because we are getting called to
this method from somewhere outside we
have to return this so let's put a return keyword
and this method now Returns the list of
blog posts back to the list page or we
will make those changes soon as well
[Music] next we have to work on the get single
blog post or the get async method and
we were doing that inside the edit page so
I'll open the logic and inside the on
get method we were using the find async
method so I will copy the statement the
highlighted part come back to my Repository
and I will replace that over here and
using the same thing I can use the
async keyword because now this is an
async method I can return the blog post
that was found from the database and it
can be null as well if the ID doesn't exist
we are left with two other functions
which is the delete and the update so
let's work on the update first we have
the update functionality inside the edit method again so I will open the class
and on the on post edit method we are
first finding the record if we found
the record we are replacing
that and then saving the changes so
let's do that let's copy from here to the
existing blog and let's take all of
this code inside our Repository
[Music] inside the update method I will
replace this line with the copied code
now we have to make this function
asynchronous [Music]
and then we have to first find this ID
so this needs to change to whatever is
coming from here which is blog post dot
ID if the blog post was found that means it
is not null then we need to replace
this existing blog post with the data coming
from the updated blog post so I can
make all of these changes over here so
instead of the capital blog post we
have to use what is coming inside of the method
and with that easy change we are now
updating our existing blog post and then
saving changes to the database finally
using the return keyword
I can return the existing blog post
back to whoever is calling us
now it's finally time to implement the
delete method [Music]
and in here we will use the ID to First
find it so we can go back to the edit
page again and we have the on post
delete method so let's expand that
and we were first finding if the blog
existed and if it was then we were
removing that blog and saving the
changes so let's do something similar let's first copy this line
and replace it here now if the blog was
found let's say if
existing blog is not equal to null then
we have to
call the DB context to remove it and
before that let's also make this
function asynchronous [Music] now let's
use bloggy DB context
to talk to the table blog posts and use
the remove method and pass the existing
blog [Music] if you come back to the
edit page it's the same thing we are doing over here
but we will change this functionality
and we will now use blog repository
instead of doing all the logic over
here so after removing the blog I want to use
the context again so await bloggy DB context
dot save changes async
and if this was successful let's return
a true otherwise let's return a false
[Music] we have this error because we
don't have
an ID because we don't have to use the
ID like that we have the ID getting
passed to us inside the method so we
will use this instead so we have implemented all the five
methods inside our repository it's now
time to inject this interface and the
implementation of this interface inside
the services of our Repository
we will do that in the next lecture and
after injecting that inside the services we will also change the code of our
web
pages to use the repository rather than
the context directly because that's a
bad practice if you want to learn more
about eraser pages and want to continue finishing
this application with me please jump to
the link below where you will get this course at an amazing price as you saw in
the introduction video this course
covers a lot of other Concepts that are needed to build an amazing Real World
blog application so what are you
waiting for jump on the link and finish this amazing course


























Comments
Post a Comment