welcome to this beginner level course where you will learn how to build a complete web application step by step
using ASP.NET core and the C# language and I spent the last
decade building all sorts of cloud-based applications that handle millions of requests every month by the end of this
course you will have master all the skills necessary to start your journey into C backend development even if you
have never created a web application before so let's get started by taking a quick look at the application that you
will build across this curse imagine that your team has been asked to build a
game catalog section of your company's video game store the frontend developers
already took care of building the web UI for this game catalog where administrators can manage the
information about all the games offered by the store now you as the backend
developer need to figure out a way to stand up the back end that will provide all the game data required by the front
end the game data lives in a relational database with tables for games and game
generous and to let the front end access all these data you will create a new res
API that will provide all the standard operations to create list update and
delete games in this course you will create this backend from scratch using
the latest Innovations in Asad net core and C if you're interested on the front
endend portion of this system please check out my blazer tutorial link to
this video where I cover how to build that part in detail now creating an hn
net cord backend involves understanding multiple Concepts techniques and patterns that I'll cover in detail in
this course you will start by learning how to create run and debok your first
spnc application from scratch then we go over the Core Concepts behind
rest apis and how to quickly implement the traditional grow endpoints in an hnet core API as you implement your res
API you will also explore the use of data transfer objects or dto to define
the contract between your API and the front end then you'll see how to use
extension methods and Route groups to properly organize your API endpoints you
will also spend some time trying out invalid inputs to learn how to ensure they are properly handled by your API
next you will introduce real database support via the popular Entity framework core or framework which is included with
the net platform this will also be a good time to explore the hnet core configuration system which will help you
avoid hardcoding important configuration details in your C code next you will
explore in detail the dependency injection design pattern and how service lifetimes work in ESPN code
applications you will also learn here how to properly map your entities to DTS
to ensure you maintain the data contract with your front end while keeping a flexible data model you will complete
your R API implementation by introducing the asynchronous programming model which
will ensure your application use the web server resources in the most efficient way and to close I'll show you how your
rest API can nicely integrate with the front end to light up a modern user
experience in order to take this course you should have some basic knowledge of C Java or a similar object oriented
language you should also know the essentials of web development and it would also help if you have some
experience with relational databases however this is a beginner level course so you don't have to be an
expert on any of these topics since we write every line of code from scratch and everything we do is explained in
detail in terms of the software prusy for this course you will need to download and
install the following the net software development kit or SDK which includes
everything needed to build and Run net applications and visual studio code a
lightweight but powerful seource code editor that you will use to write build and debug your code please go ahead and
install these tools Now using the URLs on screen if you don't already have them you will also need a few vs code
extensions but we'll get back to those later in the course with the net SD and
vs code installed let's see how to properly configure your development environment let's see how to configure
Visual Studio code to work with SPN net core applications now Visual Studio code is a
very powerful code editor but we're going to need a few additional extensions to improve our C coding
experience and also to be able to interact with our res API so the first thing that we're going to do is just
head in into the extensions view right here so let's go into the extensions View and then let's go ahead and look
for uh the C dev kit so you want to just type c here and the first kit is going
to be likely the C de kit so this is extension that you want to install so just go ahead and click on install on
this one here and the dev kit is really the an extension provided by Microsoft
that is going to overall improve the experience of coding C and working with
C projects in Vis Studio code now this extension does not install just
one extension so let me show you that uh this actually installs a few extensions if I just clear C here this is going to
install uh to start with the c extension this one over here which adds the base
language support for C inside V code so that it can recognize all of the C
syntax it of course it also installs the def git itself which is the extension that provides additional um improvements
to V code things like for instance a solution Explorer so you can more easily manage your C projects and um create C
files and also so that you can run and create test projects directly BS code uh all of that is included with a c dead
kit it's also going to install as you can see down here uh in code for C de kit which what it does is just adds a
little bit of AI assisted development as you're typing your C code and lastly it
also installs theet install tool this extension over here uh which what it does is is really a tool that provides
the net run time or the net SDK to other extensions if they need to and so that
is what we need in terms of C development now the next extension that I recommend you install is one called
rest client now this extension this is an open source free extension that uh
that I'm going to just go ahead and install by the way so let's go ahead and install it and this is going to improve the way that we can interact with our
web apis or res API directly in Vis Studio code and we're going to see that um later in the tutorial and the last
extension that you should install is an extension for SQ light okay so it's going to be the very first one over here
SQ light by Alex cbcc so let's go ahead and install it and this is going to allow us to very easily interact with
the SQ light database that we're going to be using across the tutorial all right so yeah so those are the
extensions that we're going to need and so let's now close this and let's close this pane over here now the next thing
that we should do is to make sure that well that net has been properly installed in the machine right just like
a save check so let's go ahead and open our terminal and to do that what you can do is just go into your menu
bar terminal new terminal over here and by the way a quick chart code for this
at least on Windows is either control TI right you type control TI is going to toggle that terminal for you or you can
also do contrl J is a nice way to open and close this terminal very easily all right so now in terminal what you want
to do is just verify that net is in the box so just type net D Das version and
that's going to print out the version of the net s that you have in your box you can also
do ninfo and that's going to give you even way more information about everything
that uh is related to the net SDK installation that you have in your box and with that done let's see how to
create our web project now Vis to code and by having the net SDK installed
there are a couple of ways to create your net projects the first way is directly from the terminal so here in
the terminal let me go ahead and just clean this very quickly CLS and one way that you can do this is using directly
the net CLI or command line interface so all you have to do is just type net and then you can type new and this allows
you to pick from a series of templates to create your projects now what what templates we have available here all you
have to do is just put here list hit enter and this going to give you the full list let me expand this this giv
you the full list of all the POS ful types of application that you can create with your local SDK installation all
right so for instance if you want to create a web project you could choose this one template here for instance
hbnet C empty web right that will go ahead and create a fairly empty a that that web project however since we
installed the C dev kit um there is another way that you can also do this so
let's go ahead and minimize the terminal over here let's actually close it for a moment and what you can do is just use
your command plet by going into your menu over here so just go into your menu into view Command plet right there which
by the way you can easily access by just doing control shift p which I'm doing right now control shift p we'll go ahead and open this Comm plet is super useful
there are many many many commands available here uh across the many things that Vis Studio code can do now in this
H in this command pette all you have to do is just look for net and then look for new project which is the first option over there click on that one and
this is going to go ahead and open up the list of available projects to install so the list is not as comprehensive as with the c which is why
I I like to always know how to do things via the CLI and not just via these different menus uh but here we have a
handy way to to do this right so what we want to do is to pick a template that lets us create a project for a res API
now we could go ahead and choose the aset core web API project template over here which is what you would use if
you're are more experienced with web API development but if you're new what I recommend is that you start with the xet
core empty template over here because that will go ahead and create only the minimal set of files and configurations
that are needed to get started and then you can learn slowly how the different additional pieces are going to fit
together right like Lego pieces you're going to learn how to stack each of these pieces and what what exactly is
each of these pieces doing right as opposed to start with a bunch of files and configurations that you may not
understand at the start okay so we're going to go ahead and create a brand new application with esinet core empty
web so let's click on that one and this is going to ask us to choose a directory where we want to create our project
right so I'm going to be using my D projects directory here you can use any directory in your machine but what we
want to do here is to create a folder that represents the project or the application that we're going to be working with in this case what we're
doing is creating an API for a game store and specifically the API to
retrieve or to manage the list of games the video games in our game cap so because of that we're going to be
creating a brand new project over here brand new folder sorry which is going to be named game
store okay so I'm going to double click on that one so we select the game store directory I'm going to click on select
folder down here select folder and that is going to make it so that vs code
opens that directory turning it into the workspace where we're going to be
creating all of our projects now from here the last thing that we have to choose is the actual name for the
project that's going to represent in this case our API our game store API so for that one let's go ahead and type gam
store. API let's hit enter and now vs code opens like I mentioned our
directory our game store directory and as you can see on the left side we now have our brand new game store project
created over there alongside with a solution which is the one that we can use to group the different projects that
build our application right now one thing that you should notice is that there's not one but two ways to explore
the files that got created for your project now the first way is of course the one that we are seeing right here
right this is known as the file explorer and this is showing all of the files the physical files that compose our our
current project right uh but there's also this other Explorer but you can see down here is known as a solution
Explorer and this is more of um a virtual View and let me expand this a bit this a virtual view of the files
that the files that compose your application where we're not going to see every single file for instance you don't see
either the bin or obj directories over here they are not going to be seen here because this view is more like to help
you uh manage the dependencies across different projects and also to help you create a files for C files for your
solution we're going to see how this solution is going to be very handy in several situations uh but for the most
part we're going to be working mostly with the file explorer which is going to be a good enough for most tasks now
let's do a quick overview of all of the files that got created we're not going to go deep into all of these files but
at least I want you to get an idea of what each of these files is for in your application so let's go ahead and just
close our welcome screen over here and let's go ahead and open up our program that CS file here so this right now is
the only C file that is available in your project and this few lines of code
that you can see here are the very first lines that execute when you run your application so this is the code that
pretty much boot St your application and the whole purpose of this lines here is to really create an instance of this
web application of here so app here is really of type web application and web application is what we know as a host
the host of your of your application now what is the purpose of this host well the purpose is really to represent or to
introduce an HTTP server implementation for your app so that it can start listening for HTTP request it also
stands up a bunch of mware components a login Services dependency injection services configuration Services a bunch
of services we're going be going to be talking about across this tutorial and that you can configure over here if we
expand this between between these two lines you could go ahead and always just type Builder Dot and this is going to
give you the chance to go ahead and configure a series of services depending on your needs right uh by default as you
can see there's nothing in there but we're going to be working a lot with this Builder object to introduce
Services as we go across this tutorial now when you actually go ahead and invoke built over here this is going to
build the instance of that web application and that's going to configure or set up a few things like for instance it's going to go ahead and
set up castrell as your inprocess web server that comes in with with esinet
core it also lows configurations from a few other F we're going to be talking about and also configurations for
environment variables command line arguments and many other configuration service sources it is also going to
allow us to send the login output into the console that we can see in the terminal all right and so after we have
this instance of Apt ready then we go into what we know as as as the configuration of the request pipeline so
all of these lines and let me just s here between line three and seven here is what we know as the configuration of
our request pipeline so this sets up what is going to happen when requests come in how should we handle those
requests right and right now as you can see really all all we have here is this one line over here which all it does it
says well if a request comes for the get verb this get verb into the root of my
application I'm going to reply with this Lambda expression that you can see here this is known as a Handler it just
replies with a hello world that's as all it is doing right now very very simple but you can use this app object also to
do a bunch of things like if you just type app here you to see that there are a bunch of things that you can do uh to
modify what happens when this request come in right that that's done as a request Pipeline and again we're going
to see how to take advantage of this app object across this tutorial okay so yeah
that's it for the PRS file for now now let's take a quick look at the other files are available here another very
important file is is known as the project file this gam store. api. CS Pro
what is this file for now this this is known as a project file and this one defines a few things like for instance
what type of project that you have here so as you can see at the very top here we're using the SDK microsoft. net. sdk.
web that means that this is a web project that we want by default to import a bunch of libraries and dependencies that are specific for Web
projects there are many other types of project that you can create with net but in this case we're focused only on Web projects and then if we go down here we
going to see that we have our Target framework so in this case it says net 8. Zer that means that we have access to
all of the apis that are available in version 8 of the net SD right so if you
have a lower version it means that you have access to likely less apis you have a higher version you have access to
newer apis right by the time that I'm recording this the version of the SDK that I'm using is version 8 so that's
why it defaults to net net data Z right and then there are also configurations
for other C features that are not going to dive in into right now but another thing that you're going to notice in DCS
spr as we go through the tutorial is that this is where we're going to be declaring all of the dependencies or
other libraries that that we may want to use to take advantage of their functionalities without having to write
our own code we're going to see that as we go across the tutorial now let's go back into our Explorer here and now
let's take a look at are ABS Json now we have Absa Json and Absa development Json
so these are the files that are commonly used for configurations right so this is where you would put everything that
should not be hardcoded into into your code base but more represents a set of configurations that could change across
environments right so for instance right now we already have some configurations for logging right uh but we also have
this ABS since that development Json that we could use if we wanted to so that it only works in the development
environment so in your box but these settings will not be us it as you move into production for production you could
either use ABS in Json or you could introduce other set of configurations from other sources and we're going to be
talking about those configurations later in the tutorial right now another file that we have here is under properties
there's this launch series that Json file let me collapse this for a moment now the main purpose of this launch S
Json is to provide you what we know with what we know as profiles right and we have two profiles here we have an htd
profile and down here we have have an https profile now these profiles provide you with some configurations only for
development so this is just for local development um that kind of impact the way that your application is going to
run in your box for instance this setting here states that the browser should open anytime you start debugging
your application and this one here is the URL that's going to be assigned for your application when you started this
URL by the way this port over here is automatically generated so you will likely get a different one when you create your application there's also
something like environment variables as you can see here this environment variable H netod environment is a
well-known environment variable that tells the netor time or ESP cor on time that we are working in a development
environment not in a production environment right and so nothing in this file is going to available in production
so when you go into production all of this goes away and you're you get actually into production context so all of this is really meant for local
development now just like you have HTTP if you wanted to run with https you can take advantage of the https profile
which is going to provide a another URL over here as you can see this will be the URL for https access all right now
what else we have here well we have our bin and obj directories which is really where our temporary files I mean in obj
is where we're going to have our intermediate files as we go into the compilation process and later in bin is
where we're going to have the final DLS or assemblies for our application okay
so that's it really for for the files that we have in the application let me collapse this close this and close them
now how do we actually build this project how do we end up I mean going from the code into the the binaries so
that's that's we we know as a build process and it's actually very easy to do so let me collapse this H there are a
few ways to build your project in BS code now one way and I think the easiest way to do it is by using the solution
Explorer if you go to solution Explorer down here I'm going to glap that one for a moment all you have to do is just right click in your project over here G
store. API right click click on build and that's going to go ahead and keep kick off the build process based on the
solution that you have currently right and as you can see right here we have
our dll produc it as it says right here gam store. api.dll where is it actually leaving where if we go once again back
into our file explorer into bin let me expand this a bit uh there's bin debug
because we are in the debug configuration and net 8 Z because that is the framework that we're targeting we're going to see that we have our gam
store. api. so that represents the actual assembly or the compiled version of our application okay and so yeah and
that's that's one way to do it uh but like everything else I recommend that you also know how to do this from the command line C and so to do that what
I'm going to do is just click on this plus sign over here to open a brand new terminal plus and then perhap I'm going
to delete the other one I'm going to click on this delete over there and then to build your project all you have to do
really is just type net so net C and then build uh that's going to go ahead
and and build whatever solution or project you are in so since right right now I am at the rout at game store it
builds the solution game store sln that includes the project that I'm working on right now okay so that produces the the
D and one last way to do it if you wanted to do is to by by using control
shift V control shift V which is going to tie into the native BS code integration into what we know as build
tasks right so as you can see it already knows that our our build task is do net build so you can just click there and
that's going to go ahead and kick off the build process right so many ways to do it so you can choose whatever was
best for you now how do we actually go ahead and run the application right now we know how to build it but how do we
run it it's actually very straightforward easiest way to do it is by just hitting the F5 key so if you
just hit F5 that's going to go ahead and open up this dialogue that you can see here asking you to choose what is going
to be the debugger for your application right because this is going to actually go into a debug session not just run the
application but into a debx session now of course we're working with a c application right so you want to pick C
here right and now you have to pick what is going to be your your configuration that you want to work with like I
mentioned before uh in L Json we have two profiles one for HTTP and one for https and there is also the concept of
the default configuration which is going to be really the HTTP configuration so let's just go ahead and click on the default
configuration and now BS code is going to go ahead and build the project and then it's going to kick off the debugger
with a with a debugger attached into the application and as you can see it even went ahead and open my browser and let
me expand this for a moment it open my browser and it went into executing a get
request into the API right and as you remember if you go back into vs code what happens if somebody executes a get
request if we go to per that Cs and then for a moment we expected to return a hello word and because of that that's
what we're seeing in the browser right now you're returning hello word notice that we are right now at the host and
Port that was specified in lunch settings that Jason right so Local Host 52 74 would match what we have set in
properties launch sa. Json is going to be up here Local Host 52 oops 5274 right
so that's what got launched over there but then like I mentioned this is not just running application it's actually
inside a debu session and how can we tell that we are actually in a Deb session though let let me show you that
so let me go back into vs code and I'm going to temporarily just stop the debugging session for a moment so you
can see we have this stop Buton over there we can use to just stop the debugging session so I click on that I'll click close this and I'm going to
place a break point in my Pam CS over here perhaps over there which is where
we are configuring our get request and later executing our hello word land over there so now if I hit F5 once again H BS
code is going to build the project and attaches a debugger into the application and as you can see this time we actually
a stop over here in the breakpoint line five H and from here we can go ahead if
you wanted to and start evaluating the different objects that are live now in the application right so we could go
ahead and hover over app for instance and that's going to give you give us the values of the different objects that are
available right now from from AIT core right the web application object and not
just that we could see variables I mean the Builder the app on the left side we could add what
we could check out the call stack also if you wanted to but indeed we are in a
debugging session and to continue all you have to do is just click over there over here click on that play Buton and
that's going to continue the execution now this opens up the browser once again browsing into the root of the API but we
have hit the breakpoint once again and that is because now we are inside the Lambda that executes when the actual
request lands right the first time it executed because we were booting or St star up the application and now we
actually hit the get endpoint and we are invoking the this hello word L okay so
just click on play once again and back in the browser you're going to see that it presents the hello word once again
okay so that's how you can I mean easily start debugging your application now
what if you don't want to go ahead and debug all the time which is would that would be my case like you don't need to be debugging all the time because it can
be a bit timec consuming if you keep doing that over and over again so what can do and let me just back here stop my
debugging session what you can do is either go back into Explorer right you can go into solution Explorer and you
can right click in your project over here you can go ahead and say debug and then you could do a start without
debugging right start without debugging so this is going to start your application without any debugging support notice that it was way faster
still opens the browser but it was way faster right or another thing that you can do right let me stop this once again
stop that which is is going to be also my favorite here is going to be by using the terminal directly so if we collapse
this for a moment and let me expand my terminal going to Cod these three dots and into terminal over here I'll kill
this terminal back into this simpler one okay and I'm going to switch into gam store. API which is the location of the
actual API that that we have created and I'll just type net run by doing that
once again I'm running the application right but there's no debugger attached and we are going to see in nice colors
the the logs that are going to pop up out of the application and we can clearly see where is that we're hosting
the application Local Host 5274 so by being here I can again once again go back to the browser just
refresh this and again it's going to send back hello word right and so now
that we understand how to create a project and how to build and run it uh let's now switch into slide to
understand much better what exactly is a res API in this section you will learn
what are a res API is and how it relates to Modern client applications to understand what a res
API is start by thinking about all these apps you have in your phone like your
weather app LinkedIn or Spotify these apps use a ton of data
like the latest weather information the latest post in your LinkedIn feed or the hundreds of songs in your favorite
playlists however that data can't leave in your phone which is what we know as a client because it will be way too much
data to store in your device and you want fresh data all the time anyways so
the data has to come from someware and that someware is going to be some sort of server computer that usually leaves
someware in the internet Cloud but how can these apps talk to that server in
the cloud to retrieve that data well by using an API API stands for application
programming interface and it's how a service defines the functions it provides to
clients so for instance going back to the Spotify example the Spotify cloud
service could Define an API with two functions a get recent songs function
that receives the username as a parameter and that Returns the 10 most recent songs for specified user and
there could also be a play song function that receives the song name as a parameter and that Returns the stream
for that song so that a client can play it like this there could be dozens or
hundreds of other functions offered by the service that clients can use to interact with it so an API helps clients
communicate what they want to the service so it can understand and fulfill the request rest stands for
representational State transfer and it defines a set of guiding principles that
impose conditions on how an API should should work we won't dive into each of these principles in this tutorial but
the important thing to know is that thanks to them you can build apis that are scalable flexible and independent of
the technology being used on the client and the server so going back to the original question a rest or restful API
is one that conforms to the rest architectural style now the main reason
why we want to stand up a rest API is so that our clients can interact with the
data that it manages but how do they actually reach that data well for this it's good to
First understand the concept of a resource in a res API in a res API a
resource is any object document or think that the API can receive from or send to
clients for instance in our game store application the main resource is going to be our games that's what clients want
to query and modify but in other applications like the Spotify example one of the resources
could be the songs and in in the LinkedIn example one resource could be the users and another
one the LinkedIn posts these resources will be hosted on some domain which
could be a public domain an internet location or it could be just your de
boox and they can be accessed either via the HTTP protocol or the https protocol
which is a must in public environment so when you combine all these you get what we know as a uniform
resource identifier or URI and that is what your clients will use to identify
and reach resources of a res API there could be more parts to this URI but
these are the essential elements now how do you actually interact with the res API well just like
with traditional web pages when clients want to request something from the servers they will send an HTTP request
using the resource URI to the server and then the server will send back a
response however in rest apis these requests and responses will look a bit
different depending on the specific HTTP method used to call it the most common
methods are post which creates new resources get which retrieves the
representation or state of the res resource put which updates an existing
resource and delete which deletes a resource so these methods allow you to
create read update and delete resources and therefore they are also commonly
known as Crow operations there are other methods too but for the purposes of this tutorial
we'll focus on these four ones let's take a look at each of these methods in the context of our game store example to
understand better how they work to request all games a client will send a get request to the game's endpoint and
the server will respond with something like this the first part of this response is the status which is 200 okay
in this case this means that the operation was a success there are many
other HTTP status codes that AR rest API will send back depending on the result of the operation many of them for
failure scenarios the next part is the body which contains the list of games in this case notice
that this body is not HTML but instead the format of the response is known as
Json which stands for JavaScript object notation this is the de facto format for
sending and receiving data in res apis because of how easy it is to read and write and is supported by all major
programming languages If instead of getting all games you wanted to to get a specific
game you would again send a a get request but this time you would append
the resource identifier at the end number one in this case the server will
respond with the state of the game with that identifier assuming it's able to
find the game to create a game the client can send post requests once again using the games
resource URI but this time it needs to specify the desired resource state in
the body of the request which in this example only includes the name of the game but could include many other
properties of course the server will usually reply with a 2011 created status
code and if the resource identified was not specified as part of the request body the response will usually included
to obtain an existing game the client sends a putot request with the same resource URI as they one to get a game
but this time it includes the resource State just like in the post scenario the
server will completely replace the state of the game associated with the specified identifier with a new state and will
typically respond only with a two or four no content status code finally to
delete an existing game the client sends a delete request to the URI that identifies the game to delete and after
deleting the resource the server will usually respond with a 204 no content St status code so in summary your complete
games res API would look like this and should offer all the support that your
clients expect from a modern backend let's now jump back into the code to see
how to implement this res API in a net core before we start implementing our
net res API we need to find a better way to interact with it and that is because the browser is not really designed for
this kind of work and you can only do so much from the browser so instead of using the browser what we're going to do
is find another way by using directly Visual Studio code to talk to the API and let me show you how that works so
back in BS code in our file explorer let's go ahead and just right click on
our project folder gamest store. API in this case let's do new file and let's name this file games. HTTP the name of
the file doesn't really matter what matters is extension and this file is recognized by the extension that we sted
before this one called rest CL that extension allows us to write a
statements directly in this file that very quickly allow us to interact with the API so for instance remember that we
have our hello world declar over here right so far this is all we have how do we interact with that well all you have
to do here really is just say get because it's going to be a get request and then we want to specify the host and
Port of our running API so to figure that out remember you can you can always always go into launch sajason look at
your HTTP profile this profile over here HTTP and here is your application URL so
I'm going to copy this close that I'll just paste it over there and now we are
pretty much ready to talk to the API so how that work so let me collapse this let me open my terminal I'll do contrl J
to open my terminal here I'll switch into gam store. API and I'll just do net
run right remember that there are many ways to run your application this is just the way that I I like to do so so
now what I can do and I'm going to collapse this for a bit what I can do now is just right click over here where
I have declared this line line one I just right click and I'll use this this option here that says send request send
request click on that one and on the right side I'm going to C the terminal you can see that we get a response right
away including the hello world that we were already expecting that we were seeing before in the browser now we're
seeing it here and not only that we can also see the status code of the response and a few other details about this this
response and so you can also go here I mean there is this send request link
over there that you can always go ahead and click it's going to have the same effect I have found that at the time
that I'm recording this this link is not super reliable so sometimes it may not work so that's why I prefer to do it the other way but another way to do it is
also do to do Control Alt R in Windows at least Control Alt R is going to go
ahead and execute the request for you so as you can see this is a much better way to interact with the API but one problem
that we still have is that anytime we start a debugging session the browser is is still going to open right so if I
just close this and let me open up my my terminal over here I'm going to do contrl c to stop the process process
stopped now I'm going to do F5 to start a debugging session and what's going to happen is that of course it it builds
and the breakpoint is been hit I'm going to remove this breakpoint and then the browser opens again right so this is not
something that I like because we're not going to be doing anything with the browser and even a debugging session I'd like to just stay within BS code so how
to prevent the browser from opening so let's go back to BS code and let's stop this debuging session what we can do is
just go and I'll do control shift e to open my Explorer View and I'll go into
my launch settings at Json file right and so in this file all you have to do is just switch launch browser from
through to false and I'll do that both for my HTTP and my https profiles right
we're not going to be using really https but just in case uh let's switch it in both sides all right and just by doing
that if I hit F5 once again I'll hit a five you're going to notice that we just remain within BS code and if I want to I
can go and just close this and I can go ahead and right click in my gam HTTP and
send a request right which now it is sending the request but we are in the context of a debugging session which is
going to be super handy in many occasions all right so yeah so let's now stop this let's close this this and this
and let's go back to the Explorer view control shift so now it is time to start the implementation of our API uh but
there's one thing that we're missing so far and that is a way to represent the
resources that we're going to be managing in this API right like we said we're going to be managing games video games right it's a Catal of video games
that we don't have a way to represent those if you remember if you go back into pram CS I'm going to collapse these properties also in pram CS uh we have
already defined this one well by default we get this map get that all is doing is just returning this hello word right
which is a simple string but in our case we may want to have multiple properties that are associated to our games that
we're going to manage so things like an ID a name and a few other things right so what we're really missing here is
what is known commonly known as a data transfer object now data transfer object or dto is an object that carries data
between processes or applications it encapsulates data in a simple and standardized format that can
be easily transmitted across different layers of an application or across different applications so let's see how can we go
ahead and Define a dto to represent our Gams so let's go ahead and just close
this file and for this we're going to be using actually the solution Explorer down here solution Explorer let's open
up that uh and we're going to be using this anytime we want to create either folders or files for our project because
it's just easier to do it here than in the standard Explorer so right click on the G store. API let's add a brand new
folder we're going to name this folder dtos now keep in mind that other folks
like to name this folder contracts as opposed to dto which is totally fine because a dto can be considered like a
contract between the client and the server because it represents the shared agreement between client and server
about how the data will be transferred and used so if you want go ahead and name these contracts that that would be
totally find is just really the same thing now in this directory let's right click on the TOs let's create a br new
file it's going to be in this case is going to be a record not a class but a record right and let's name it game dto
okay now why why are we using record types here as opposed to a standard class well the thing is that by default
records are immutable meaning that once their properties are set usually at the time we create these records they cannot
be a changed right and this immutability is a perfect fit for dto uh because they
typically carry data from one point to another without the need for modification and on top of that records
reduce the boilerplate code that is typically associated with class definitions intended for data holding
like DTS as as you're going to see you can Define these records with just a single line including all the properties
which simplifies the code base and makes it much more readable and it has I mean record types have many other benefits
but these are the main ones that I see that are very useful for dtos right so let's go ahead and let me
collapse this so how do we Define this EO first thing that we should do here is to actually match the Nam space with the
file structure so let me open up my explor again remember that this is under our DTS directory and because of that I
like to always follow the structure of my file system I like to follow it also in the name space so for that you can
either type here just. dto or you can use this this liel over here you can click on that and you can select the
option that says change namespace to gam store. api. dtos right so that's going to make make it so that it matches right
let's collaps this and now let's define the properties for the dto now D is actually very easy to Define we don't
actually need this coolly rases all we want to do is just open parenthesis here and here we can start declaring our
properties the first one is going to be our ID that's going to be an INT int ID
and then the next property is going to be a name uh let's follow that with a gener so
gener is like is it sports racing role playing whatever kind of game we're dealing with we also have a price and
then at this point by the way let me just send this to the next line so we can see better what we're working with here okay we have the price and lastly
we're going to be specifying a release date for that one we're going to do uh date only date only release release date
and we're doing only because we don't really care about the time all we care is about the date portion of the of the date when the game was released right
awesome so now we have our dto ready and now we're ready to go ahead and start taking advantage of it so for that let's
go ahead and open our Explorer view once again control shift e and let's go into program CS let's collapse this now as we
start writing the next few lines just keep in mind that our API is going to be evolving across this tutorial right so
you you may see that the initial code that we write for this is going to be a little bit dirty and odd uh but is is meant to start like that just so that we
can solidify the initial concepts of res apis first and then we're going to see how to refactor and get into a a much
better implementation and in that sense what we're going to do here is to define a very simple list of games in memory
using our dto class we're going to see how to implement the different HTTP methods along or around that in memory
lease later in the tutorial we'll see how to transition from that me in memory lease into an actual database
so what we're going to do here is just perhaps just after the the definition of our web application object over there
we're going to declare here a simple list of our game dto right and notice that by selecting game dto BS code
automatically added a using a statement over here game store. api. dtos right so that it just did it by by itself and
that what that's what gives us access to the game type now the name of this is is going to be just games and we're going
to Define that list right here now I have already prepared a small list of
games just for us so just so that you don't see me typing so much so let me just go ahead and grab that list from my
other window over here as you can see I have now three games right so here is just my favorite games right so ID one
is going to be Street Fighter 2 the generator is fighting now we have the price here and we have an M here because
we want to specify clearly that this has to be a decimal right otherwise we're going to be we're going to get kind of a
warning here because the compiler will not know if it's decimal or double what is this right so it's going to be decimal in this case and then we have a
date only in this case here's the date for that first game and then scrolling down we have a id2 Final Fantasy 14 role
playing here's the price here's the date and lastly we have another of my favorite games FIFA 23 with ID3 Sports
here's the price and finally the release date all right now how how do we go
ahead and actually uh Implement an API that can return these games over here
right and so for that is actually we can actually follow the pattern that we have down here right so what you do is you
say okay you use the web application object and you say okay so what kind of a verb I'm going to implement in this
case we want to do a get right a get operation so it's going to be map get and then you want to specify what is
going to be the path under which this endpoint is going to be located right in
this following proper rest practices we should name this as games because the
API is going to be all about managing games now notice that this is not going to be named just game right it is game
in plural because that is the way to address the group of resources you're going to be dealing all right it's very
important to keep those conventions like that now after you define that pad what
you must specify is is the Handler right so how are you going to be handling a request that comes into that pad so in
this case really all we have to do is just return that Lista we have in memory there so we're going to do just this
games so this land Expressions just says that we're going to be returning whatever is in the games list over there
and really all that's all you have to do and this is really why this type of API
is known as a minimal API because it is very quick very easy to to declare as you can see over here now let's see how
what how that works uh in practice so I'm going to go ahead it and just run my API once again and I'm going to click on
these three dots into go into terminal and I'm going to delete this last one so I'll just do net run all right
net run and then what we want to do is just go back into games. HTTP and what we can do is just modify
this one uh request that we have here to to actually Target our API remember that it is under the games games pth so I'm
going to just copy games over here slash games and that's pretty much it so I'll just
right click I'll do send request and as you can see on the right side we get a
200 okay response so it was a success and down here we have the actual games
so notice that we have here Street Fighter 2 we have Final Fantasy 14 FIFA 23 it's all there and then like I
mentioned before this is a Express in Json right so espinet core took care of
Transforming Our C objects serializing them into Json a as you can see right
there all right so yeah so that's our get endpoint and then now let's go ahead
and close this and let's go back to pram Cs and let me also control J to open my terminal contrl C to stop it uh one
thing that we may want to do at this point is just get rid of this hello world because we don't really need it anymore so I'm going to rep it now just
so that we can keep track of what exactly each of these endpoints is expected to do I'm going to add a little
bit of a comment here so this would go for a get get games right so whenever somebody
goes into get games uh this is the that's is going to respond okay just as a little bit of documentation now what
we want to do now is to perhaps create the request that can be used to retrieve not all the games but just one game how
would you do that get Again by ID so it's a very similar idea actually so what I'm going to do is just say perhaps
let's do the documentation first it's going to be something like games slash a one for instance how do you represent
that so app mapet okay and so again we start with
games but this time we need to provide one more thing which is going to be the identifier in this case so for that in
this what is known as the pattern we can specify with this corly Braes we can introduce a kind of um the variable that
we're going to be using to receive that ID right so that goes in the row template and then in the next parameter
for the Handler what we're going to do is now not receive just an empty argument list but we can actually
receive that ID that we specified there with the exact same same name int ID
right and then this leads us into the actual execution that we want to to perform here so what we want to do in
this case well just find the game that has that ID so for that we can just use uh the find method of of Leist so games
to find and then we will do game where game. ID equals the and just like that
we should be ready to go ahead and query for for one specific game so once again let's run our API the that run in the
terminal close this go back to G HTTP and what we want to do now is to H just
add another request here now to separate your request in this file what you want to do is just introduce these three
pound signs and then you can add your request and I'm going to copy the first one down here notice that because we
have this three pound signs we also get the send request link over there which means that it is recognizing it so we
without without these ones it would not do that right it just goes away make sure that you add that and now that I'm
here I'm going to um just append slash and then we want one of the games so
let's do number one and then let's right click let's do send request and on the
right side you're going to see that we are indeed getting that game number one right you can see it's game number one
right so yeah very simple and very very similar to what we did before right so
let's close this and let me control C stop my server back to
Broncs before we move forward uh notice how we keep using the proper rest notation as we Define our end points
right so for instance in this case when we did games by ID we prefixed everything with the name of the resource
or the plural of the name of resource in this case games and it has to be like that right so you cannot say something
like get games right that will not be correct it has to be games or you cannot even say something like um games
uh games by ID and then something like this right that will make no sense so to
follow proper reson notation you always start with the grouping or the the term that represents the group of resources
and then you follow when you want to specify something or find something by ID you followed by with the IDE of the
identifier or of that resource right so this is the right way to define resources in rest if you're not doing it
this way you're not doing res right so now let's move forward to the creation
of brand new resources how do we do that well we have to create a post end point for this but before we can do that we
need to Define how is that or what is going to be the representation of those resources we're going to be receiving
into that ID it is it is similar to the one that we're using today for I mean the game dto for return resources but
it's not exactly the same one right let me show you how this should actually look like so let's let's go back into
our Explorer over here and we are in solution Explorer and what we're going
to do is right click on DTS and create a brand new file and again it's going to be a record not a Class A record and
this one is nam going to be named create game dto all right and then once again
let's go ahead and fix the name space and here's one tip for you uh anytime you see a libel over there instead of
clicking on it you can just do control dot control dot is that that's going to open up this context menu and then you
can pick whatever makes it this case change name space to Gam store. api.
and that will fix that now to Define thisto here we could grab a bunch of the properties that we have uh in our other
I mean in our game DT over there let me let me go ahead over here I'm going to paste those but there is just one
difference I'm going to paste those over here and the difference is that when we
create again we actually don't have any ID right the ID is going to be provided by the by the server by the API itself
so we are not going to require clients to send us an ID because of that we're going to be removing this from there so
we STI with the name the gend the price and the release date now this the is
going to be changing later on in this tutorial this is just an initial version but for now notice how the contracts
that we're going to be using either for returning data or for posting data into the API uh may be different right so
that's why we want to be very specific on what we're going to be requiring from the client for each case all right so
now that we have our create game dto let's go back into to pram Cs and we can
go ahead and Define our brand new endpoint so the endpoint is going to be for the Post Verve when somebody post
something into the game's handpoint and just as before what we can do is just say app that in this case is going to be
map post okay and of course it is when somebody post something into games and
in this case in our Lambda what we're expecting to do is to actually receive a
object object of the type of our dto the run new create game dto and let's just
name it this one as new game all right now what are we going to do in this case
so let's go ahead and actually expand let's have a body for this one so we can be a bit more verose in this case what
we want to do is just to uh kind of convert this create game dto into a normal game dto just to add it into our
inmemory Leist for so for that let's just do game dto G it's going to be a
new okay and let me open and close here so the first parameter here of course is
going to be the ID so what is going to be the ID of this game now how are we going to come up with an ID Well for now
what we're going to do is just add a plus one to whatever count of games we
have so far so in this case we're going to say games. count and we're going to say just plus one all right that's going
to be our ID then we go for for the name so that's going to be new game. name and
then we go for the generate so new game. gener then new game price and lastly new
game release date right so that's going to go ahead and complete the definition
of our brand new game and then let me scroll down bit we can do is just say
games. add our game right so the game is part of our list and lastly what we want
to do is return something back into the client to tell the client what was the result of the operation did it succeed
did it fail what happened and we can provide even more details and the standard in this case is to return a
2011 created response how do we do that so all you have to do is just say return
and you can use the results class right so this a this a buil-in class in infinite core results and then this
contains multiple prebuild responses that you can use so you don't have to manually specify the status of the
response so in this case we're going to say is created at Route okay and then we
use this because with this we can provide a location header back into the client so the client knows exactly where
to find the resource that just got created so how do we do that so the first parameter here is going to be the
the name of the route where the client can find that resource now we have not actually defined the name of that route
so far uh but but to do that that what we're going to do is just go back a little bit into our map get by ID route
over there and just before closing this we're going to just do here dot with
name right and this is a method that you can use specify to give give a name to this Endo that we have defined because
it doesn't have a name so far so what name we're going to give it so let's just name it get get game okay so get
game and then now and now we can use this exact same name down here
in our order in our return created by ad route get name get G and C is going to
take care of figuring out what is the route to to that endpoint right and to use it to build the location header to
return back to the client okay the next parameter I want to specify here what is
going to be the the value that needs to be provided to the get game route remember that get game receives an ID
right here it receives an ID and so we need to provide that ID back into the response that we're going to provide here for that we're going to be using I
mean the standard is just to use anonymous type so we're going to say new and in this new we're going to declare
that it has an ID and that ID is going to be game. ID the one that we
autogenerate last parameter here is going to be the actual payload that
we're returning back into the client if you want to return a payload so for that we're going to be using game all right
and so now just to keep things a little bit cleaner uh what I like to do is is is to not have this name repeated twice
right over there and down here and instead of that let's define a constant that we can use uh to refer to this to
this value so let me just copy this and let's go all the way up here okay before
declaration for list we're going to define a con string this let's name this one get game and point name and that is
going to be get game okay so now we can just copy this constant down here we can replace that
in with name right here this is the get game m point name and down here we can use it all right that way we avoid
having this hardcode this all right so with that in place we are ready to go ahead and test our brand new post
endpoint so open the terminal and I'm going to just do net run all right so it
is running so let's class terminal let's go back to gam HTTP and of course what we have to do is Define a new request
here so triple pound over there and then we're going to be doing a post request it's going to be same endpoint right
with no ID right it's just the endpoint games endpoint and then one thing you have to specify here is the content type
right so so that we can tell our API what kind of content we are sending over there so in this case it's going to be
content type and the content type in this case is going to be application Json right and then uh in this case
we'll have to Define just leave one empty line over there you need to leave this one empty line and then in the next line this line 10 in this case we're to
define the payload of our of our game we're going to be Crea remember that the payload has to include a name general
price and release date as per our create game dto so back in HTTP here's HTTP uh
I'm going to Define that but just to not write too much I'm going to actually copy it from my other screen over here
here's our first game so this is going to be as you can see it has a name gener
a price and a released right in Json format so we that in place and since our
server is running we should be able to go ahead and ex execute this so I'm going to just right click here and I'll say send request and as you can see on
the right side we are getting the expected 20 one created response over there okay and then down here we can see
the payload that represents the game that was created right notice that it has the id4 it's a fourth game in our
list and it not just has the payload down here but it also provides us with the location header right notti this
here here's the location header uh that ainet core created for us because we provide Ed the the right values for the
created at Route method that we us right and so and since we have this the client
knows that now the client can just use this I'm going to copy this I'll just copy that close this and the client can
go and say for instance let's say over here we can replace that and now we can
right click and send send request and now the client was able to query for that brand new game right there game
number four and of course if we execute the first request we should be able to see that we have total of four games
over here one two three and four here's the four games all right and yeah that's
it for the implementation of our get a let me just stop my server here and let's go back to
prcs so now we're able to query for games and create brand new games so how about updating existing games right so
for that of course we're going to be needing a a put endpoint but before that
just a before we need a brand new dto to represent the payload that the client should send when they want to update the
resource so let's go back into our cont shift e our Explorer here this is solution
Explorer right click on dtos add new file record and then this is going to be
named update game dto now we could certainly just use create game dto for
the same purpose uh but really the convention is to always specify a brand new contract or dto for every single new
operation because eventually things could change right it would it could be that you may need to do something
different for upd dates that is not needed for a creates and so I don't want to be messing with those contracts so
just keeping them separate one for each operation right so let's go ahead and
collapse this and I'm actually going to H go ahead and grab what we have in create right now so I'm going to copy
this into update because like I said right now it's the same thing could change later but for now it's just it's
just that and with that dto in place let's go back into program. CS run that
CS over here and let's define our put endpoint so I'm going to move down here
let's go and do this so we can see better and let's define our app and by
the way let's define that this is going to be for a put into games right and so
app. map put in this case map put and then once again this is going to go into
games and then just like in get by ID we need to specify what is going to be the ID of the resource that needs to get
replaced right put in here means replace resource with whatever I'm going to be send okay and then uh we are going to
specify two parameters in this case h is going to be inside our arguments Lambda
um the ID we need that ID that we just specified in the template and then of course the update game dto updated
updated all right now let me just check one thing yeah we forgot to fix name space over here
we should always have the the correct name space so let me do control dot here to change space to G store. api. dtos
all right and then what do we do about the body of this Bo so let's open up our
body for the Lambda right there and what we're going to do here is just H find
the game in the list the existing game in the list for the ID provided and we're going to then replace that game in that list with a
brand new representation right so so let's first find find the index of the
game so we're going to say index it's going to be games. find index and then
for the game where game. ID is it that we got as a parameter so that gives us a
in game and what we can do now is just go into our list games and then at the index of the found game we're going to
create a brand new game dto right so let's open and close parenthesis and
then of course here we're going to be just filling the filling the slots right so it's going to be the ID and then we
have updated game. name updated game. gener updated game. price and updated
game that release date all right and so with that we have replaced uh the the
game in the list and last thing is to return something back to the client now the convention for an update is to just
return no content right so return results. no content and that will be
pretty much it for our put operation now uh you may notice that there we are not
covering all of the cases right in this API so far like what happens if I cannot find the game right so we're going to go
back into those uh later in the tutorial for now I just want to get a complete set of endpoints that we can work with
and then we're going to go back and start refining these endpoints with whatever pieces we are missing okay so
for now just happy back so now we have our input defined let's go back into our
gamat HTTP and let's see how we can query a send a request for this put
endpoint so just like before we're going to open a brand new section this is going to be a put right it's a put
request now let me just copy this the endpoint goes into SL games but
of course like I mentioned we want to specify in this case we need to specify the ID of uh of the of the resource that
we need to replace so in this case it's going to be SL one let's say for to replace the very first game that we have
in the list and then well what is that game so to know that let me actually start our server so let's go ahead and
do net run so we can start a server let's query for all the games right so in this one here right click Send
request right so what is the first game is this one here Street Fighter 2 what I'm going to do is just copy the body of
this first game just going to copy it and then down here I'm going to use that
for our put body now let's not forget to use content type application Json over
here and then let's paste that down here looks like I didn't copy it properly I'm
going to just grab it from my other screen there here we have and what I did
here really is just modify the title right notice that the initial title uh as we can see right here was um strict
Fighter 2 right price is $19.99 so I'm going to make a small change so that the
game is now going to be named St fighter to turo and then the price is going to be just way cheaper it's going to be
just $9.99 right those are the two changes that we're going to introduce into this game but just keep in mind
that putot is going to replace the object right that's the purpose of put replace the object completely so with
that in place let's go ahead and right click and hit send request and as you can see as expected we get the 204 no
content that's the expectation that's good and then if you want to verify that things the the game actually changed all
we have to do is just go and query for game with ID one in the get so right
click Send request and on the right side we should be able to see that yeah indeed now it is a street fighter too
and then we have a brand new price order right so the put operation is working as SP right so let's close this and stop
our server back to pron CS now before we move on into the last
operation the delete operation one thing that you have to consider here is that um er concurrency right what happens
with concurrency now now keep in mind that all the the thing that we're doing here is really a starting point towards
something we're going to be doing next but if you ever decide to just go into production with this in memory list of
games keep in mind that this is not going to work very well because games is a simple list right so games is a simple
list that we have over here and this list is not threat Save Right meaning that if you start getting multiple
requests let's say into put over here right you could go run into issues right
imagine multiple requests coming here and trying to modify the same game at the same time that is not going to be threat safe that's going to cause
problems so don't do that in that case you want to be using something different than a Leist perhaps a concurrent back
or something like that just not a simple L uh now in our case we're going for this because like I said this is just an
initial implementation for you to get started with rest apis and later you're going to see the we're going to get rid of that list and move into something
much more interesting right and so let's go ahead and Implement our last endpoint and this is going to be our deleted
right so let's scroll down here and documentation this is going to be a
delete for the games pad and then we need to specify some sort of file right
so just like before map in this case is map delete map delete and we want to specify where is going to be the pad in
this case just gains and then it has has to have the ID of course and then we
specify what is going to be our argument in this case it's going to be just the ID in ID and then let's open up our
Lambda body over there and let's see what would we do for a delete but the delete is actually as you expect the
simplest thing to do all you have to do is just remove any any game that matches
that for that what you can do is just say games that remove all and then where
the game is game that I ID equals ID
that's all and then uh the expectation for the delete is again a no content
just like in the update case so you can do return results. no content that's all
it is all right so and well to test this very easy let's go ahead and run our
server once again the Run let's go to our file over here I'm going to grab the
location from the previous request and I'm going to just add here another
request down here now in this case it's going to be um delete into whatever part
we have over there and then um yeah that that's pretty much it let's say let's say actually work going to the game
number two right and so now before we delete let's confirm what we have initially right so right click at the
very first request we have three games right now one two and three we're going to be deleting number two Final Fantasy
14 so let's right click on let's close this and right click on our delete request send request it says no content
204 no content meaning this is successful so now we can go back and get our full list once again send request
and on the right side you can see that we no longer have a game number two so
we have one we have three we have two it is gone so our delis is working as aect
all right let's close this and let's stop our server and back into
prones now at this point our API is mostly functional however we have only
dealt with happy pads right so we still need to deal with a few unexpected scenarios for instance what happens if
we are not able to find a game right and let's try it out so let's go ahead and
run our server all right and now let's go back into games.
HTP and uh let's try to find again that does not exist so if we go back into our very first request we know that we have
games one two and three that's fine now let's use our second request to request game number four right what happens if
we request game number four so right click Send request and what we can see on the right side is that not only we're
getting a 200 okay which is already bad right because I mean there's no game why are we getting a successful result we
even getting a null response down here so this is this is just completely wrong
this is not what we should be returning there's a standard way to reply
for a situation where the resource cannot be found and that's what we're going to cover now let's close this and
let's stop our server and perhaps we can close a few of these tabs here to simplify our screen move this here so
let's head back into our get by ID get by ID method over here so this one over
here so first thing we're going to do is just to give a proper body to this uh to
this method so let's open C right there let's do this all right like that and
then what we're going to do is to actually capture the result of the call to find right so we're going to say well
far gain equals games. find okay now what are we actually receiving from
games. find if if we not notice closely we're receiving not just a game dto but a nullable game dto right and to make
that more obvious let me just do control dot here on V bar and let's use an explicit type as instead of bar right so
this is a a nullable game Theo that means that we could either receive a a game or we could receive null if we're
not able to find game because of that what we can do is to alter the response to our endpoint here to return the
correct response depending on if we found the game or not so we can say is
well return we're going to say if game is null right so if it is null uh we're
going to return we're going to be using the results results class to return not
found right this a standard response where we're not able to find the
resource and otherwise if we're able to find the result the the resource uh we're going to say in this case well we
cannot just say game right because now we're returning two things right one
side we're returning an object of type I result and on the other side we're returning an object of type gain
nullable and that's not allowed that's why we have this cruly Braes over here so because of that we're going to wrap
the game into results. okay okay that
will make sure that for both cases we are always returning the same type of ey
result all right and yeah that that's pretty much it so if we run this once
again so let's run the API right so running it g. HTTP now let's try to
retrieve game number four once again request and you're going to see now we get the proper 404 not found there is no
null down here and this is the expected response when we're not able to find a
resource all right so yeah so that fixes the case of our um if our get by ID
request now let's see what to do about our put request right because I mean post is fine but put could face the a
similar situation so if you're not able to find the game this find index call is going to return a min one so in that
case we should not move forward and we should R again return and not found so we're going to do is just say if index
is actually minus one so that's the response minus one we're going to say okay result return results. not found
now one thing to keep in mind here is that returning a not found for a put
call is kind of um is one of the possible things that you could do uh for put and it's not really clear in rest
terms uh if this is the absolute true of what you should return because another thing that you could do in this case is
just to go ahead and create the resource if you don't find if you can't find it you could go ahead and just create a brand new resource with the payload that
we receive over here right and that's what many services do but many other services will just return and not found
what to do exactly it is not clear it is not clearly defined so it's really up to you to decide what what to do in these
cases now I do prefer this way of returning not found because in the case
where you H actually choose the other option where you create the resource you run into a bit of a problem when um you
move into a scenario when you actually have a database uh that is able to
create the the IDS for the resources by itself um and in that case if the ID
over here said well ID is going to be I don't know five and then you come here and you cannot find the resource and you
go ahead and just go ahead and create a resource uh the the database will go
ahead and create the resour we whatever ID makes sense right so it's out incrementing usually right and that may
not match the ID that you specified here right so you get into a weird situation of what do we do about that that
identifier when we are not able to find a resour with that for a put request so because of that I do prefer this method
here but just keep in mind that it is totally fine to all to choose to just go ahead and create the resource if you're not able to find it in a put scenario
right so let's go ahead and test this and make sure this works so net run let's go into gam HTP and in this case
we're going to go ahead and try to do a put for let's say game number five which
does not exist let's see what happens if we try to do that right click Send request and as you can see we are
getting now a 404 Note file so our new logic is working awesome so let's close
this and let's stop our termin and back to pram CS now what about our delete
endpoint this one over here should we do something about the fact that the game may not be there well as you can see it
doesn't really matter right because we're just removing whatever we can find that has the specified ID right and
that's okay for a delete verb the object of delete is to delete the resource if if it is there if it is not able we're
not able to find it it is fine the client is not really doesn't really care on the fact that it found it or not as
long as a resource does not exist anymore after invoking the delete operation all right now uh well now we
have our endpoints pretty much uh implemented right at least the basic behaviors and then one thing that maybe
bothering you at this point is that well we have I think just too much code in our pram that CS file right so this is
just becoming a big file and that's a big big no no right we should we should be able to put all this code in
somewhere else to keep our PR CS as clean as possible so because of that what we're going to do is the following
let's go back into our Explorer control shift e and then uh let let's collapse this and what we're going to do is just
create a brand new directory in solution Explorer so gam store. API right click new folder let's name this folder
endpoints all right and in the new endpoints directory we're going to right click and we're going to add a new file
unless this is going to be a class and this class is going to be named games and
points yeah games and points that's a name all right and as usual let's do control dot at the very top here to fix
our name space so it is st. api. endpoints right there and let's class
this now this is going to be what is known as an extension method as extensions class or I mean going to be a
static class that's going to have extension methods which are going to be H static and the idea of this class is
that we were going to be able to extend one of our classes or the classes that we don't own like the web application
class so that with just one call we can map all of the endpoints that we need for our API let me show you how how that
actually works so first this class has to to be static okay so we can have our static sanction methods inside and then
we're going to start transferring all of the code that should not really be in pram CS anymore so we're we're going to
start with this const and the list that we have here let me copy this we're
going to copy that over here all right and then let's make sure that we import
spaces I'm going to do control dot on game dto to use G store. api. dtos all
right so here we have our Le now since we are in a class now we have to we should provide a proper ident um
modifier for the type of access that we should have for this games list so in
this case this is going to be a private list all right and we have cool races here because it is suggesting that we
should make this field read only which makes sense uh because uh even when we may be adding and removing methods into
this H adding or removing games into this list we're never going to be reconstructing the entire list from
scratch right that's never going to happen and so because of that we can make it readon right now it is a readon
list okay now is have squiggles here uh because we are declaring an instance
member in what is really a static class right this static class so because of that we will have to make this list also
static and really everything here is going to be just static now with that in place we can move forward to actually
declare our extension me like I said this is a method that is going to extend the functionality of an existing class
and it happens to be a class that we don't actually own but we can still extend it so let's do that public static
and then we have to uh decide here what is that we're going to be returning from this method here and what we're going to
be returning is just going to be the exact same time that we're going to be extend right as kind of a convention so
that type is going to be web application all right that will allow whoever calls
this method to just chain another call into uh into another extension method that is also extended with web
application if they want to now the the name of this method is going to be map
games end points and then this is going to receive web application and let's
name it yourself now to make it so that this is actual an extension method all you have to do is just put this here and
that turns this into an extension method so now our method is going to show up as a new method of the web application
class right now what what should we put in the body here well let's go to program Cs and just grab all of the
methods that Define all of our end points for our API so all of these let's copy that and let's paste those over
here right so our method looks like this map gain end points and we start adding
all the map gets map post map put and map finally since we are returning a web
application object we should just return up okay and uh yeah that will do it for
our map gain Senter end points uh extension method right we just return app at the end with that in place we can
now go back into pram Cs and we can clean things up so we can go ahead and
pretty much remove everything between app and app. run or we can just get rid
of all of these and all we have to do now is say app. map games
endpoints right so as you can see now our perm CS is very clean and I'm going to do control dot at the very top to
remove on usings like that so that's all we have now in our prcs and now we have
our everything that relat is related to endpoints in games end points. CS right
now it it is possible to forther refactor this of course you should do that but in this story we're not going
to go that deep into refactoring we want to move forward to another set of very important topics regarding R cpis and
one of the topics here is the fact that if you notice we have um we have this
games uh endpoint right in multiple places across the API right so we have it there we have for the map get by id M
byid and then we have it for every single endpoint we have games gam games all over the place so can we do
something to improve that we certainly can and to do that what we can do is just take advantage of something that is
known as a group Builder right so we can create a group that defines common things across all the endpoints so that
we don't have to Define them over and over how to do that so let's scroll down a little bit and all we have to do here
is say well our group equals app. map
group okay and in this map group we can say that okay so all of my routes for
this specific set of endpoints are going to start with games right everything starts with games and with that we can
take this group variable and make it so that all of the gets post and all of these calls go from group so I'm going
to replace app here with group group and then the same thing for every single
method here so group and then group and group okay and since we have changed
everything into that group variable we probably want to also go ahead and return that group down here as opposed
to the app now group does not map the web application so we'll have to change the return type into route group Builder
right so let's go all the way up and let's change from web application into route group
now of course what's the point of doing this well the point is that now we don't have to say games all over the place so
in this case we can just say slash right because this is this get is going to go go just after the games that's over here
right still goes into slash games like this but it's going to be because the
get is changed into the group that we created up here all right so for the second one we can remove games right
it's just SL ID and same thing here a post is just is going to be like that
for put it's going to be like this and for delete same idea all right so that's
one way to avoid having to repeat the same name over and over again right that's that's what we know as a route
group Builder Okay and then well let's make sure that things are still working properly so I'm going to just run the
API and let's just check that we can go ahead and engage that HTTP we should be
able to list all of our games so let's send a request so yeah that seem working just fine and I'm going to just test one
more think our post right click Send request and it is working as expected right so it's all good awesome now the
next thing that we should work on is well what happens if we receive invalid inputs right so in this case like for
instance in the post case this one over here what happens if somebody posts um a
payload with without a required element right for instance we should not be able to send and let me scroll down here we
should not be able to post again without a name right so you should always have a name what happens if I just do this and
send it like this we're going to try that out let me see yeah so my server is running and so well let's right click
let's hit send request and let's see what happens right so notice this so the
resource got created so 2011 no problem but now not notice this we got a null in
the name so the API allowed us to just create an invited resource and that is
not good so in this case what we should be returning is really a bad request right uh because it is a validation
error and the input is not correct so we have to do something to account for those cases right so let's close this
and let's see what we can do so let's go back and this time we can just close for MCS and let's focus on games end points
now if you go down into my post over here right uh well there's a couple of
ways to deal with this right I think I think the the the manual world to manual way to do this is well uh as soon as we
receive the post request we could Su something like well if uh stream. is n or mty perhaps uh new game. name right
uh we could go ahead and say well return we can do results. bad request right and perhaps
we can even add a a little message here that says name is required right so that
would be the basics that that you can do if we execute this I mean that should certainly work uh okay so we're running
let's go back to G at http click here send request and that works right so now
we are getting a bad request which is much better and we even have a little message down there so that's okay
however of course uh this is going to start becoming a little bit uh challenging right because uh if we let's
go ahead and stop the server server go back to games endpoints uh because name
is not the only property right we have a bunch of properties here to deal with that could have many different kinds of validations that we need to perform in
there so we're going to end up writing a lot of code here um perhaps we we even have to do the same thing for the put
request right so this is not the best approach so what we want to do is to introduce some sort of proper validation
uh into our dto and there are a few ways to do that so here I'm going to show you the simplest and and most basic when way
that you can use in net to do validation and that is by using data annotations so
let's H let's actually undo this we're not going to be using this really right
and let's go back into shift e or Explorer let's go into create game DTU here's our dto class so we can do here
is to use this concept of data notations so data notations are nothing more than just attributes that you can apply to
your properties and that can Define what is expected of these properties for
instance for the name we can Define here that the name is required right the name is required I'm going to do this control
dot here to import the system component model that data an notations name space and even more I'm going to say that uh
our name should not be really that big let's say that our name should be at much let's say 50 characters right not
nothing more than that so we can do string length of 50 like that okay so
with that any anywhere we use this great game dto that validation should be automatically applied that's the idea
behind this okay and then um for the gener let's do something similar but
let's do perhaps gener doesn't have to be that long perhaps only 20 that will be good enough and then for the price
well price is not a string uh but perhaps we don't want to accept prices of I don't know thousands or millions or
even more than that perhaps we can say that the price should be in a range of
one to 100 that should be good enough for a price we don't have video games that are more than
$100 um of price I mean that would be that would be crazy um and yeah that's
pretty much it so that defines the data notations for our H for the creation of
our right and this is remember cre GTO is the one that we receive here in the post however that's not going to be
quite enough right if we just go ahead and run this okay run that and we go into g. HTTP if we go ahead and now run
this H post request request it still is not doing the validation right so notice
that we still get created we still got a n there so is not working uh so those data anotations will work just fine in
the in the older core MBC framework but when you do minimal apis you need a little bit of
more support and at this point what you want to do is to use a new feature
called endpoint filters endpoint filters is a feature that comes with minimal apis that allows you to validate what's
coming in into your into your endpoint and do some sort of validations around it right now and let me let me just
close this and let me stop my Ser now we could use endpoint filters manually
ourselves uh but there's Act a better way so there are nuget packages that already wrap the right endpoint filters
that can tie directly into the data notations that we're using here so that we can easily enforce these validations
right so what I want to do is to show you a nugget package that you can use to automatically perform the validation so
let's let's actually go into let's go into nuget.org and by the way if you're
not familiar with nouet nugget is the is pretty much the package manager for net and so there are hundreds and hundreds
probably Millions well thousands or millions of n packages are already available that can simplify many things
for you so you don't have to write your code manually so in this case we're looking for a very specific um nouet
package let me show you here so I'm going just type here minimal apis. extensions you search for that this is a
free nugget package well everything is free really here uh open source nugget package that is able to help us in this
case so I'm going to grab the latest version here I'm going to just copy the command here for net CLI copy that and
let's go back into vco so I'm going to open my terminal and I'm going to just paste
that line so package minimum API extensions in this case I'm using version
0.11.0 and hit enter all right and so at this point if we take a quick look at
our let's see gam store. API project this is our project file CS BR notice
that now we have our first package reference this means that now our project is able to use any of the types
classes defined inside that net package and because of that we can do the following now so let me go into G
endpoints now under our post over here we can go ahead and say just before
ending we can say dot with parameter validation which is one of the methods
provided by that n package okay and just by doing this the appropriate endpoint filters are going to be applied and are
going to recognize this data annotation that we specified in great game video so now if we just go ahead and uh run our
API okay it is running back to games at HTTP let's execute our incomplete
request send request and notice that not only we get our bad request as we should
uh we even have a nice error message down here so let me show you uh nice error message that says okay so one or
more validation errors occured we have a status 400 and we it even tells us exactly which field uh is
missing right and so and this is this is very nice and in fact this is actually
tied to the proper RFC that you can see over here uh which is the right way the standardized way to report errors back
into clients so that clients can easily read these errors and act accordingly right and we were able to do all this
just by using one nouet package right now if we go back into the code uh one
thing that you should realize is that um you can can do this parameter validation not just for one endpoint you can
actually apply it for all of the endpoints all of the endpoints by using your grout route group right remember
that we have a group here this group over there so what you can do now is just say um actually we can just change
it here we can say dot with parameter validation and now these validations apply to any of the endpoints that are
going to be receiving one of these uh DS that have data notations right and in fact we are doing validations right now
for create G dto but we should do the same for our updates right our they should also be validated so let's open up update game DTS dto and then well I'm
just going to go ahead and and copy this because it's pretty much the same validation we're going to apply right
there same validations and make sure that we import the right in space and now both create and update should get
validated so let's go ahead and run our API let's make sure that all of these validations are working properly right
so let's go back into G http so we already verified H the create for
an empty name now what happens if we try to do a very long name right so Minecraft Minecraft Minecraft big name
like that so I'm going to right click here send request okay let's see notice
the error now the field name must be a string with a Max a maximum length of 50
right so the length is getting validated for that request which is is correct right let's uh let's go back to to this
uh what happens if we have a uh if we don't have a generate let's see right click and then send request yeah the
gener field is required so that's good and let's do something about the price right we said that the price should be at much 100 so let's see if you try a
price of 119.99 right click Send request and as
you can see over here the field price must be between one and 100 so that's
all working just fine and lastly let's go ahead and verify that our put is also validating right so let's remove the G
the name from the put and let's use a valid a ID let's do id2 right click and
request and as you can see once again we get a bad request my request over here
and uh if you go down there yeah you can see the name field is required so yep
it's all working as expected so now we have properly validated endpoints all
right so let me go ahead and just stop our server okay and uh with this in
place I think it is time to start moving away from this ink memory list of resources and actually introduce a
proper database for our res API and to do that we're going to be using a very
handy framework that is part of net that is known as Entity framework core so let's switch briefly into slides to
learn more about Ed framework core and why it's going to be super useful for our development here in this section you
will learn about the object relational mapping technique and how Entity framework core can help you write code
that interacts with your database without having to learn a new language at this point we want to add database
support to our res API so that all our data is persisted beyond the lifetime of
the application so whenever a request to create a game is received in our API we
want to create that game in the database and when the client requests a list of games we want to query that list also
from the database however there is a problem the database does not speak the same
language as your esinet core API your API is coded in C but your relational
database server only understands the SQL language that means that to fulfill that
request to retrieve games your C code needs to translate the API request into
a carefully crafted SQL query and then send that query to the database
server the database server executes the query and then your C code has to read
back any resulting rows and translate them into a corresponding API
response this presents a few problems as a c developer you now need to learn a
completely new language SQL in order to graft the required queries and you need
to learn it well to to ensure you get good performance out of it you'll need to write a lot of additional data access
code whose only purpose is to translate things from C to SQL and vice versa and
of course deal with unexpected errors talking about errors this approach is
error prone since it's very easy to make mistakes when mapping things from one side to the other and you need to
manually keep your C models in sync with the corresponding database tables which
can be quite challenging this is where object relational mapping techniques or orm can make a big
difference but what is orm well going back to our Spotify example imagine your
application has been created using an objectoriented paradig and therefore it
includes objects to represent songs artists and playlists and if you're working with a
relational database server there's a good chance your database will have corresponding tables for each of those
objects now instead of having to write custom code to map these objects to
tables each time you need to send or receive data to or from the database you can set up a map between them so that
your program can keep working with objects while another component an object relational mapper takes care of
transforming objects to tables and vice versa so in essence object relational
mapping is a technique for converting data between a relational database and
an objectoriented program and as you can imagine it brings many benefits to
application developers and fortunately snet core includes a great orm framework called
Entity framework core so what is Entity framework core it is a lightweight
extensible open source and crossplatform object relational mapper for.net Entity framework core will sit
between your res API and your database server besides mapping your donet objects to database tables it will
translate your C data access code into seq statements that the databas server
can understand and it will also translate any resulting data from the database into objects that your API can
easily manage using Entity framework core in yournet applications brings in
multiple benefits there's no need for you to learn a new language you can perform all
data access tasks using your familiar C language the actual data access code
that you need to write is minimal since Entity framework takes care of most of it in fact you can use language
integrated query or link to perform most of your database queries there's tooling
available to keep your C models in sync with your database tables so you don't need to do this manually anymore Entity
framework can keep track of the changes made to your C object instances at run time so it knows what changes to send to
the database when it's time to persist the data also Entity framework cor supports multiple database providers so
you can use your same C models with other relational databases if needed
let's now see how to use Entity framework core to add database support to our game store R API the first step
towards adding database support into our API is to define the class or classes
that are going to represent the data model model of our application now could we just go ahead and use our dtos for
that um you could try to do that but in general that's really a bad idea remember that the dtos represent the
contract between your API and the clients right and that should rarely
change however what we want to Define now is the data model so this ties directly into the database tables that
we're going to be using in in our database and we want to have the flexibility to change those tables and
to lay them out in a relational structor that may not match those contracts those DS that we have already defined okay so
because of that and to have this flexibility we want to keep those separate right so let's not touch the
dto at this point and instead let's go ahead and in our solution Explorer let's create a brand new directory which we're
going to name a new folder is going to be entities okay the entities are going
to represent our data model and then let's right click click on entities and let's add a brand new file and this is
going to be a class and this first class is going to represent not our gains but
actually our game generous because in our database we don't want to just store simple strings
for every single game right for sports racing and all that uh we want to have a proper table where with all of the game
generous and then have a relation between our games and our generes so let's define first our gener table for
our gener entity right there okay and for this class let me collapse
this for a bit right there for this class first let's go ahead and fix our name space as usual like that we're
going to have just two properties here so we're going to do prop and then this is going to be an INT is going to be the
ID and this the second one is going to be string the name now we do have a
small warning here right for name that says notable property name must contain a nonn value when exiting the
Constructor what this means is that we have declared a variable that is not nullable right it's a simple string not
nullable string and yet we have not defined any default value for this for
this property right and so the compiler is complaining about this and it's asking us to to provide either provide
some value or declare the Val the variable as n so there's a few ways to fix this you could start by just doing
like something like this if you wanted to that will initialize the variable as an empty string another way to do it
would be to say Okay so this actually going to be a nullable string like that uh but we don't really want to have H
nules in our G names right so a better way to do this is by actually using the
required keyword over here required and by doing that you're saying that whoever
goes ahead and constructs instances of gener we have to make sure that they provide a value for name when they
construct the object right whichever way they use to constru the object they have to provide a value for name right so
that's a very handy way to deal with new lables incision right so now that we have a class for the generate we have to
Define another entity in this case for the game so let's right click again on entities new file class and this is
going to be our game okay once again let's fix name space like that and let's
go ahead and define the properties for our game so if you remember we should have here an ID
then we should have our name so this is going to be our name and same thing we
want to define the name as required just like this it's required scroll down a
little bit and then we need to define the generate but now as you know we are
going to be using a relational model to associate the game with the gener uh
because of that we're going to have to do two things the first thing is that we need to Define uh a a property to
represent the ID of that gener that's associ to the game so what you can do is just say generate ID okay so this is the ID
that is going to be connected to the ID of generate in the gener entity but we
also have to specify another property here of the type of gener itself so it's
going to be prop type generate and I just call it gener now this property
here may or may not be null right depending on if we decide to populate
generate when we read data from the database via at framework we may decide to populate generate or not right
sometimes it may be just enough to have the gener ID so that will be populated but not the gener so since it's not
clear at this point if we are going to have for sure a value all the time so we can totally go ahead and just declare
this as a n just like that okay sometimes we have it sometimes we will not have it okay so that this
combination of two properties is what you do on Entity framework when you want to do an Association in this case a onet
to one relationship between game and gend right and so let's scroll down a
little bit more and then let's go for our price which we know it is decimal
that's a price and lastly let's go forour date only release date and with
that we have defined the two entities that represent our data model now it is
time to add proper Entity framework support into our API and for that we're going to be needing a nuget package so
let's go into nuget.org over here okay and we're going to be looking for a
brand new nugget package so let's search for microsoft. entityframework cord. SQ
light so SQ light is the database engine that we'll be using uh for this tutorial
okay it's going to be the first hit over here and keep in mind that you could be using really any other relational
database here like SQL Server if you wanted to but but for this tutorial I'm keeping it very simple with SQ light is
the one that lets you get started very quickly but most of the code that you're going to see me writing from here on is
going to apply the same way to other relational databases like SQL Server the
only thing that changes really is what provider you use for Entity framework in this case we're going to be using the SQ
provider if you wanted to use SQL Server you can just change SQ for SQL Server
right and now you have a provider for SQL Server all right now this case let's go for
sq8 and I'm going to copy not the 900 preview let's go for a stable version in
this case I'm selecting 8 802 I'm going to copy this let's go back
into our code okay and let's just paste. net package this micros framework cod.
sqlite version 802 all right so now our API is ready to
take advantage of Entity framework now let's close this terminal and let's close close this so let's go back into
our solution Explorer in this case and what we're going to do is create a brand new directory to store any of our data
related classes so let's right click on game store. API new folder let's name this one data and then in our new data
directory let's go ahead and right click we're going to be adding a brand new file it's going to be a class and this
class is going to be what is known as a DB context uh now in this case let's go ahead and name it game store
context right gain store context let's collapse this and let's just fix our name space very quickly change name
space to gain store. API that now G store context should inedit from DB
context DB context okay now notice that uh this imported Microsoft Entity
framework core this is a new imported name space uh but well you may be wondering well what is a d context right
so D context is really an object that represents a session with the database and that can be used to query and save
instances of your entities right so this is the intermediary so if you're familiar with either the repository or the unit of
work patterns um the DV context is a combination of both unit of work and repository right now to properly
construct your G your DB context you're expected to receive here you should receive what is known as DB context
options so DB context options of the type of your DB context in this case
game store context right let's just name these options okay and let's send this to the
next line let's send over those options to the base Constructor like that so
those options are the ones that are going to provide the gain store context all of the details about how to connect
to the actual database all right now the next thing that we're going to need in our game store context is some sort of
representation of the objects that need to be mapped into our database right and so we know we're going to Beal with
games and with game generes right so because of that we're going to do the following we're going to declare prop
and it's going to be of type DB set so DB set of type of the actual entity here
so it's going to be game that's entity and we can name this one games okay now
what is a d set well a d set is really an object that can be used to query and save instances in this case of game so
any link queries a language integrated query queries uh against a d set in this case of type game will be translated
into queries against dat right and to provide an initial value for for games
what we can do instead of this is just point directly into H we can use this
method set of type game okay that's going to create our DB set instance all
right and just like this one we're going to create another one dbet of type J and let's name it
gems which is going to point to a set of type G our context is ready to go ahead
and map our objects our entities into proper database Tes but what we have to
do now is to tell our application how to connect to the database to our cite database using this
gain store context and for that we have to register the context on start app so let's go ahead and go back into our
Explorer view over here and let's go into pram CS over there pram CS and
here's where we have to start using our Builder object to register Services right so down here what we can do is the
following first let's go ahead and Define a connection string so let's just
name it Con string it's going to be so how do we actually connect to sq light so it's actually super simple this is
why what I really like sqlite all you have to do is specify here data source
equals and here you specify the physical PAAD into your database file right so in
this case let's just call it gam store. DB okay now here you could specify some
other pad in G store. DV if you don't want to have it directly um at the root
of your project uh but for the cases for the case of this tutorial I think it's just fine to have it directly under the
the project directory right but you can specify really any other physical pad so yeah that's a connection string and with
that connection string we can go ahead and actually register the service and to do that what you want to do is you say builder. services and then in
this case add SQ light and here we want to specify the name of our context the
one that we just created so game store context and then we want to pass in the
connection string okay now this is taking advantage of a mechanism that is known as dependen injection which we're
going to be talking about later in the tutorial uh but important thing to know is that because we are adding this
Services here Entity framework is going to take care of reading this connection
string right and then it is going to create an instance of our gain store context and it's going to pass in DB
context options over here that are going to contain all of the details that are in that connection string so that it can
connect to our database right and map the entities to tables however there's one thing that's not really ideal here
and that is that we have the connection string right here in the code right now in this case it is SQ the has nothing
really wrong there I mean there's no secrets no credentials it is incredibly simple that is fine however it's still
not really great to have the code for the connection string right here because as you change into another environment
let's say into a production environment you're going to have to change your code here right to point to an actual production database and that's just not
idea so you want to keep this information this configuration data outside of the order code base so to
understand where we should be putting this connection string let's go ahead and back into the slides to understand more about the AET core configuration
system at this point we have hardcoded the connection string to talk to our database directly in our application
code however this is not ideal since eventually when we move the API to a
different environment like in a cloud deployment the connection string will be different and we would need to make code
changes which is not ideal fortunately there are better places to store
application configuration one of the most popular options in hnet core especially for
local development is the absen Json file which can store all sorts of
configuration information in Json format now the absens the Json file is what is
known as a configuration source and just like that one there are several other configuration sources supported in net
applications like command line arguments environment variables user secrets
and even cloud-based configuration sources like Azure key volt and the
great thing about this is that the SB net core runtime takes care of combining information from all available
configuration sources into a single configuration object that implements the ey configuration interface this
configuration object is easily accessible to your res API in such a way
that it doesn't really need to know where the configuration data actually comes from in this tutorial you will use
the apps Json file to store your connection string but keep in mind that
this is an acceptable option only because you don't need to use any credentials to connect to your SQ light
database if for local development purposes you are using a database server
instance that requires credentials please use the user secret configuration Source instead which is enabled by the
snet cord secret manager never restore any kind of credential in your
appsetting Json file let's now update our res API to read the connection
string from the appsetting at Json file let's see how to take our connection string out of program.cs and into our
upset. Json file so let's go ahead and open ups. Json and what we want to do
here is to introduce a brand new section that we're going to name connection
strings now this very specific element called connection strings is a well-known element of net meaning
that there are apis that are going to be looking specifically for this one word here Nam connection strings so make sure
that you type connection strings just like I'm doing right now now inside this
element you can introduce one key for each of the connection strings that you
want to introduce into your code now in this case we want one connection string for our game store database so I'm going
to just type here game store you can really type any name here but just make sure that is something that's related to
your database okay and then on the right side we want to introduce the actual value for this key now what value we're
going to use let's just go to pam. Cs and copy the connection string that we have been using so far okay and then
let's paste that over here all right so now the connection string is outside of our code and we go back into prom Cs and
like I said there are apis specifically designed to read these connection strings and let me collapse this for a
moment and what we can do now instead of just H reading the hardcoded word is use
the Builder object to get access to the configuration object over here which is the one that implements I configuration
and is the one that collects configuration information for every single configuration search that has
been configured for your application like I mentioned in the previous lesson in this case this is going to include our upside adjon file and because of
that we can just say get connection string then we pass in the name of the
key of our connection string so in this case case in say that Json we remember that that is game store so I'm going to
copy game store and I'm going to paste that over here all right and that's
really all you have to do to read your a connection string fromjson now let's
confirm that this is actually working by placing a break point over here perhaps in l seven to see what value we read
into connection into const string so with that done I'm just going to go ahead and press F5 to start a debuging
session so F5 and this should be one of the first lines that is hit AS application starts all right so
breakpoint has been hit and so let's see what value we have ofation string as you can see data source equals. DV is
exactly the value that is being read from our set the Json file all right so
that is working perfectly which is great so let's just stop this session now at
this point our application is pretty much ready to talk to our database however the database itself this sqi
database does not exist just yet we need to go ahead and create it and to do that we can use a process that is known as
migrations so this is the Entity framework process that takes the different entities that make up your
data model and turns them into corresponding tables in your database
that are properly mapped to those objects and before we can do that we're going to need to install when additional
tool so let's go back into our nugget page over here and let's look for a tool
called net EF okay this is going to be the first hereit over here so netf is a
tool that you can use to do all sorts of Entity framework related task against
your application now in this case I'm going to pick version 8.0.2 which is the latest stable version at the time that
I'm recording this so I'm going to just copy this command and let's go down here
vs code let's open our terminal let's switch to gam store. API and let's just
paste that command okay so this line here is going to install netf this is not just a nuget package it is an actual
tool that you can use to execute a the frame related commands so I'm going to hit enter notice that this also installs
a tool as a global tool right that's why we using Global over here meaning that you can now use it from any net
application that you have in your machine now the next thing that we're going to need is an additional nugget package and so let's go back into nuget
gallery and let's look for this package called microsoft. Entity Framework core. design now this package here is the one
that is going to be used to actually generate our enti framework migrations so let's go down here let's pick our
latest stable version 8.0.2 I'll copy this and back into BS
code I'm just going to paste that here hit enter and the package is now installed in our API project right let's
close this so now we're ready to generate our first migration now we have to decide where we're going to to
generate this migration if we look at our Explorer over here what we want to do is just to generate a folder under
our data directory we're going to place a new folder which is going to contain our migration which is going to have all
of these mapping code between our our C code in and database right so to do that
let's go ahead and open up our terminal once again going to clean this and perhaps let me expand this a bit more so
we can see better so make sure that you are in the gam store. API directory this over here and then you can execute the
following command you can do netf migrations at initial create you can use
any name here this is just the name for the migration that we're created since it is the very first migration I like to
call it just initial create but you can use any other name and then we're going to give it the output here it's going to
be under data like we said the data directory and then under that directory let's create another one called
migrations all right let's go ahead and execute this okay like I said it is built and then the migrations execute
now what actually happened here so if we go back into our Explorer let's close this now we should have under data as
you can see now we have a brand new migrations directory over there open up that and you're going to see a few new
files I'm going to go into all the details of these files but one thing that we can take a look at is this very
first file initial create notice that this is going to have kind of um of
number that is somehow related to the date and time that we are generating this migration on right and so if I
click on this file let's see what we have here so as you can see so this is a class that extends from migration it's
called initial create and this going to have uh this the following methods so first is going to have this up method
which is the one that is used to move to the next H migration that the database is missing right so this is known as the
up method then but we also going to have a down method that could be use it to go back to the previous state of the
database now if we go back into our up method notice that here is where the actual tables are going to be created
right so migration Builder create table here is the name of the table generous right because our DB context defines
this generous D set then generous is going to be created as a table and here are the columns for the table right
which are going to be created in the context or in the terms of the database server that we're are using in this case
we're using SQ light so because of that it is creating a table with a type integer in the for the ID column and
then with a type text for the name column right it also sets up a primary
key for the for the ID field in the generous table and then we move on into
the other table the games table over here that defines an ID name General ID
price and release date right with corresponding values for each column notice also the the ID is is going to be
an AO incrementing column meaning that anytime we insert a value into this table uh a brand new number sequential
number is going to be assigned for the ID okay then we also have our constraints here we have a primary key
for the games table on the ID column and we also have a foreign key that relates
our games table to the ID column in our generate table that means that every
every ID that we use for Generate ID in our gam table has to exist in the gener
St all right that's a foreign key constraint lastly we are creating an index for the generate Ed column in the
gam table all right and like I said in down what's going to happen if we decide to go back into a previous version of
the database uh it's going to just go ahead and drop the gain table and then it drops the generous table in the
proper order all right so yeah so that is the migrations process and now our
codebase is ready I mean the codebase now knows how to go from nothing and into the actual database so what we have
to do now is to execute this migration so that it it's getting it gets applied
into the database so let's see how to do that let me close this and this and and let's go ahead and open our terminal
here let's clean this and really all you have to do to execute the migration is to use again netf and in this case the
command is going to be database update so let's hit enter so net Entity
framework is going to locate that migration code and it's going to execute it against our machine right away so
let's take a quick look at what's going on here so you're going to see a bunch of Entity framework related commands but
you can see how the table gets a gets the tables get created now the first table as you can see here in this in
this section here is the EF migration history table so this is a table that's going to be used to keep track of what's
of what's migration migrations have already been applied into your database right that's how Entity framework knows
what is missing from your database if you add new migrations later right so that's the E migration history table now
if we keep going down we're going to see that here's where Entity framework Noti
it that we have to go ahead and apply this BR new migration that we created that's what's going on here and then
later it goes ahead and creates the gner table as you can see creates G table and
then we keep going down and we will go ahead and create our games table right
here right and then it will end up creating the indexes and finally it sets
a brand new value into EF migration history for the brand new migration that we just execute right so that happened
seems like it was a success now how can we actually take a look at that database and make sure that it got actually
created right so let's go back to our Explorer view over here and one thing that we we going to notice now is that
we have a brand new gang store. DB file over there right now the reason while
this file which is a file for our sqli database got created directly under our game store API directory uh is because
of how we Define our connection string right if we go back to abs. Json I'm going to close this remember that we
said that the file would be just in gam store. DV which mapped directly into the root of our project now if you wanted to
uh I mean you could move this file somewhere else like for instance you could do something like I want to have a DV deer like like that and that will
create a that would place a database into that DV deer under your proct directory uh but just make sure that uh
I'll be aware that you have to create this directory manually before doing that uh otherwise entity will not be
able to create your database right now since this just for local development I think it's just fine to keep the databas
like this but one thing you may want to do if you're using git for instance is to make sure that you exclude this file
from your git comit right in on Gore so that the file does not get checked in
right so now we have our H file over here but how do we actually get into it now remember that we installed this
skite extension for BS Cod that means that we have the ability to pick into that database and to do that let's just
right click in game store. DV and let's use this very first element over there that says open database click on that
and by doing that notice that a brand new Explorer showed up over there on the left side SQ Explorer so that is going
to allow us to start looking into what's going on in the database and if we start expanding these notes here we're going
to see the structure of the table right so we have generous with an idea and a name and then we have games over here
with an ID name gener price and release
date there um lastly we also have like I mentioned we have our EF migrations
history table right there which like I said this is the one that keeps track of every single migration that we are executing against the database now if
you just right click cck on the EF migrations and we select show table that's going to show us the current set
of values inside that table as you can see this just one value over there and it even keeps track of the version of
Entity framework that we're using so far all right so yeah so our our database
now exists and our application is ready to start start working with it now let's
go ahead and close this and let's go back into our file explorer now one
thing that I like to do to simplify things a bit is to have a little bit of code on Startup that takes care of
applying any missing migrations when the application starts that way we don't have to run the Entity framework command
to update the database every single time that we add new migrations so let me show you how to add some some of this
code so that the migration just happens as soon as as application starts all right so on our data deer and let me
actually switch into solution Explorer now under our data deer I'm going to right click and add a brand new file
okay it's going to be a class and this one let's name it just data extensions okay so this is going to be
an um an static class to hold a brand new extension method so let me let me
now collapse this oops let's just go back to the file right here okay so
let's fix our namespace contol dot let's fix it to gamestore api. dat like I said
this is going to be a static class because we want to put an extension method here and let's introduce a brand
new method here that we're going to name going to be static because it is extension method migrate DB okay and
this method is going to extend the web application object application class all
right and what we want to do here is to go ahead and migrate the database so
there are API in the framework to go ahead and migrate your database however everything that has to
do with our database needs to have an sculped Lifetime and we're going to be talking about dependence injection and
these lifetimes in in a moment uh but for now what we need to know is that we cannot just access the DV context
directly we need to provision a scope that allows us to actually start
interacting with the database right so let me show you how to do that first we're going to be getting an instance of
a scope so to do that let's do this using bar scope equals uh
services. creat scope right so that gives us a scope and let's see what type
is is this is an i Services scope right that we can use to request the service
container of ainet cord to give us an instance of some of the services that have been registered in the application
now remember if you go back into program. CS over here pram CS we have
executed this line here right at SQ light this this line here is going to register our game store context in the
service container right meaning that aset core knows about the type and is ready to provide us an instance whenever
we request one right so if you go back into the extension what we can do is the following we can now say d context
equals scope service provider. get required service what service we need we
need the game store context service Okay
and like I said we're going to be talking about about more about this dependency injection and services codes uh in a moment uh but for now let's just
use our DB context to get access to our database and from there we can access
the migrate method over here which by the way imported a brand new namespace at the top over there Microsoft Entity
framework core all right and with these few lines we are now ready to execute
migration on Startup now all we have to do is go back into PR Cs and invoke that
method so I'm going to do that actually close to the end just after map game end points I'm going to just say app.
migrate DB right we can use this method because it extends our web application
uh object over there all right now to verify that this actually works what I like to do is just to well delete the
database right delete the database and the application when it starts it should go ahead and recreate the database
automatic right this is one of the reasons why I like to use SQ light for learning purposes because it's very easy
to use right click on the V here and delete the database right yep delete
it's gone okay now let's go back into our terminal over here going to clean
this and I'm going to go ahead and do net run and let's see what
happens as you can see all of the all of the statements uh go ahead and perform
the migration executed as you can see over here all of the statements executed just before stting the application and
gam store. DV is right there regenerated all right so yeah that work just fine
and simplifies a little bit the way that we execute these migrations now one thing that I don't don't like and let me
just stop my server for a moment is having so many statements every time the application starts right because from
here on any time the application starts Entity framework is going to be logging whatever is doing to our database if
needed so one thing that we can do is to uh simplify a little with these logs right so we don't have to see so much
right it is fine if we need to but login can get very BOS so how do we actually switch this loging a little bit so that
we don't have to see so much every time it starts so let me cross this let's go into absence. Json over here and what we
can do is to um add just one more entry into this section login which is the one
that configures login for our application we can add one more entry to change the login severity of one of the
elements of our application so for instance in this case if we go back into the terminal right for instance all of
these statements that says hey I'm executing this command here and this command there right uh this I think
that's just T BS like all also here but all of those statements are coming from this one name space look at this
Microsoft Entity framework code. database. command so we can say we can do is say hey uh for anything that comes
out of the Microsoft framework code. database. commanding space please only show me warnings or errors right or
something critical but do not show me just information messages right these are all info as you can see on the left
side these are all informational messages what I'm going to do is just copy this let's see if we can
copy close this and I'm going to add an entry into here to configure a different
lock level for that very specific name space right I'm going to say that for this one one I do want to use War okay
and by doing that I'm saying hey I only want to see either warnings or errors or something critical but not anything that
is really less severity than that okay so if you now go back into the terminal
and let me actually open my Explorer I'm going to delete the database once again let's see what happens different this
time so I close this let's clean our screen and let's do net
run notice that now the output that we got here is is way different right there is no mention of all of these commands
that are executing in there all that we are going to see here is this line here that says applying migration something
something and then if there was any problem with that migration or with any of the commands it would show up here uh
but otherwise the console it is just very clean right there's not much going on there so doing this is something
optional I mean if you want to see all those commands every time H just feel free to not and not do what we just did in ABS Json I just like to keep our
command line as clean as possible all right so let's stop our server and go back to our code just close of that and
let's go back to our file explorer now as you know we have this concept of game
categories in our application right so things like sports racing or playing and all that and for those values that are
which which are pretty much fixed across the application we're not going to be creating apis to to create or modify the
categories we're just going to go ahead and populate the categories when the application starts right and to do that
we can use a very simple process of data seating that we can introduce directly
into our game context or game store context object so let me show you how to do that let's go into our data directory
and into our game store context over here and what we're going to do if we scroll down a bit is to add a brand new
method just under our latest DB set and let's let's go ahead and overwrite we
want to overwrite the on model creating method this one over here on model creating all right so let's scroll down
and this is one of the methods that going to be executed as soon as the migration is executed right so when you
execute the migration this code over here is going to execute so this is an opportunity for us to do things that
slightly modify the model according to our needs and one of the things that we can do here is to populate some very
static data right now I'm not going to I would not do this for data that requires much more complex operations right this
is just for some some things that are very very simple and like I said this is just a list of categories now to do this
what you have to do is just say model builder. entity and then the type of entity is generate and then we're going
to be using the method called has data right so this is going to make sure that
whatever data we introduce here has to exist when the migration process
completes okay now here what you want to do is to introduce well as many elements as you need for in this case for the
gener so for instance I can say new and then I'm going to say well ID equals one
and this is going to be our name equals and the first category is going to be
let's say fighting all right so there we have our first element and let's go
ahead and spin up a few more categories I'm not going to just type all of them let me grab them from my other screen
here now we have um five categories that
we can work with right so fighting roll playing sports racing kids and family feel free to use less or more of this as
as you want but yeah so just by having this code here all of these H these five
categories are going to be created as the the migration executes so now for that to work we of course need to add a
brand new migration right because otherwise Entity framework doesn't know that it needs to map these to the
database so to do that let's go ahead and open up our terminal and let's let's add a new migration so net EF migrations
add and now we want to use a new name for this migration so let's say seat JIS
all right and once again the output output here is going to be under data
migrations right let's go ahead and hit enter all right migration completed let's see what happened on our Explorer
over here migrations now we should have a brand new file so you can see we have C generous right here C generous let's
click on that one let's see what happened over there now here we have a brand new up method so here's up and
then here the migration Builder is executing the insert data method over there to go ahead and into the generous
table is going to insert these five values all right so that's that's all we
have to do and for the down method you will go ahead and delete all of those values that you got inserted all right
and once again like I mentioned I would only do this for very very simple data that does not need to interact with any
other objects in the application because remember that you're not actually running the application at this point you're just doing some static work as
you're applying the migration right so only for very simple stuff and static data that is not going to really change
so if we go ahead and run the application now right so net run run
application okay notice that the new migration got applied over there see generous got applied and if we go into
our database okay let's collapse this let's go into our gam store. DB actually
SQ Explorer if we go ahead and right click on generous I'll say show table
let's see what we have let me collapse this let me close that and that as you
can see here we have our five generates now as part of the actual tape right so
they're right there is live data that we can now use in our application all right
so that is complete let me go ahead and just stop my server now we are approaching the moment where we actually
need to start changing our res API to take advantage of our new DV context and
all this Entity framework stuff but before we can do that it is very important to understand this concept of
dependency injection because remember for MCS we are using dependence injection to register this the the game
store content into ainet core but what does that registration means and what is all of this depend injection concept
about so let's switch to slides so we can better understand the concept of dependen injection in this section
you'll learn about the dependen injection design pattern and the multiple benefits it brings in to your
applications to understand what the pendis injection is let's start by looking at two classes my service and my
logger my service uses the log this method meod of my logger to log messages
to a file anytime my service performs an important operation since my service
uses some of the functionalities of my logger like the log this method we say
that my logger is a dependency of my service now in order for my service to
start using my logger it creates an instance of my logger in his Constructor and after that it can start
calling the lock this method at first glance it doesn't look like this presents any problems but consider what
happens when the authors of my logger decide to slightly modify it so that a
new my file writer object needs to be passed on this Constructor because that's where the output file is now
defined the required changes look simple to implement but they reveal a few
important problems my service is tightly coupled to my logger in such a way that any any
time my logger changes there's a need to also change my service as it happened
here when the Constructor started requiring a my file writer instance my
service needs to know how to construct and configure the my loger dependency
like is the case here with the my file writer object which needs to be configured with an appropriate file to
send the output lcks this makes it hard to test my service since unit tests
won't be able to mod or stop my logger an output. log file will always be
created which would slow down tests and this assuming that the test have access
to a place to write files to fortunately there's a better way to do this using what is known as dependency injection
let's go back to my service and it's my logger dependency my service it still
uses the log this method but this time my logger is not explicitly constructed by my service instead my logger is
passed in as a Constructor parameter my logger is injected into the my service
Constructor this way my service doesn't need to know how to construct or configure the logger it just receives it
and can start using it right away but if my service doesn't construct the logger
who does it well snet core provides the I service provider which is what is
known as the service container your application can register my logger and
any other dependencies with I service provider during starup which is typically done in your program.cs file
then later when a new HTTP request arrives and your web app needs an
instance of my service the service container will notice its dependencies and it will go ahead and resolve
construct and inject those dependencies into a new instance of my service via
its Constructor this enables multiple benefits for your application to start
with my service won't be affected by changes to its dependencies it doesn't matter how many times the Constructor of
my logger changes there is no need to change my service moreover my service
won't be creating instances of my logger so it doesn't need to know how to construct or configure it if your
application uses minimal apis dependencies can also be injected as parameters to your minimal API endpoints
finally dependency injection opens the door to using dependency inversion but what is dependency
inversion the dependence inversion principle states that code should depend on abstractions as opposed to concrete
implementations let's bring again our my service class and it's my logger dependency currently my service depends
directly on my loger which allows it to write logs to an output file but let's
say that now we're moving to the cloud and we need to start sending logs to some sort of cloud service for this we
would like my service to start using a new Cloud loger class we could modify my
service to receive and use a cloud logger instance instead of a my logger instance however what we can do instead
is modify my service so that it depends on a new ey logger interface instead
which provides all the required login functionality then we can have both my
logger and Cloud ER implement this new interface with this we are decoupling my
service from the logger dependency allowing it to use my logger Cloud logger and any future logger
implementations without ever having to modify my service the only thing that
the different loggers need to do is to implement the interface that my service depends on in terms of the code this is
how you would now inject the logger into my service so the main benefit of of
using the dependency inversion principle is that dependencies can be swapped out without having to modify the class that
uses them but also it is now much easier to test my service since the loger
dependency can easily be mocked out or stopped and finally your code is now
cleaner easier to modify and easier to reuse now before we start using the bend
injection in our code there is one more important concept to understand which is the service lifetime
we now know the basics of dependency injection in ESP core we know that on Star app your application will register
the dependencies like my logger here and later when an HTTP request arrives I
service provider will resolve construct and inject an instance of my logger into
a new instance of your class my service in this example what is not clear is
what happens when a new request comes in should I service provider create a brand
new my logger instance for the new request or should it reuse the same instance what if another service that
also has a dependency on my logger needs to be created in response to a new request sa my logger instance or new my
logger instance the answer to this lies in the service lifetime which you
configure when you register my logger with I service provider there are three available service lifetimes so let's
take a look at each of them let's say that my logger is a very lightweight and
stateless service so it's okay to create a new instance every single time any
class needs it in that case you would register my logger with the at transient
method when the first HTTP request arrives the I service provider as usual
will resolve construct and inject a new instance of my logger into my service however when a new HTTP request
arrives I service provider will construct and inject a brand new instance of my logger
which has nothing to do with the first instance furthermore if there's any
other service that participates in any of these HTTP requests and also has a
dependency on my logger it will also receive a brand new instance of it so
transing lifetime services are created each time they are requested from I service provider
what if my logger is a class that keeps track of some sort of state that needs to be shared across multiple classes
that participate in an HTP request in that case you would register my logger
with the adcode method here when an HTTP request arrives the I service provider
will again resolve construct and inject a new instance of my logger into my
service but if there's any other service that participates in that same HTTP
request and that also has a dependency on my logger it will receive the exact
same instance of this dependency however if a new HTTP request
arrives the service container will create and inject a brand new instance of my logger instead totally unrelated
to the previous instance so esope lifetime services are created once per
HTTP request and reused within that request finally let's say that my logger
is not cheap to instantiate and it keeps track of a state that should be shared
with all classes that requested during the entire lifetime of your application then you would register my
logger with the at Singleton method as usual when an HTTP request arrives the I
service provider will resolve construct and inject a new instance of my logger into my service and if there is any
other service that participates in that same HTP request and that also has a dependency on my logger it will receive
the exact same instance of this dependency but furthermore if a new HTTP
request arrives the service container will once again provide the same instance of my logger to any of the
classes that requested and it will keep doing so until the application is shut
down so singletone lifetime services are created the first time they are
requested and reused across the application lifetime now that you understand the benden injection in h net
core and the different service lifetimes let's get back to the code and see how we can use these Concepts to use a DB
context across our API endpoints we just learned about the Bendis injection and service lifetimes
but how are those related to our DB context well going back to pr. CS let's
look at this line here line seven builder. services. atsq light with gamore context
this line is actually registering our DB context gam store context into the service provider which is a service
container and it is doing so with an scope lifetime so it may not be may not
be evident here but when you see this line what's really happening under need at some point is something like builder.
services. add scoped with game store context right and there's of course more
going on than than just this but this is the key part so gamar context is getting
registered with the service provider so that later on anywhere in our code base we can go ahead and inject that instance
of gain store context into our code so that we can take advantage of its services now why why is this gain store
context registered with a scope Lifetime well by doing a scope lifetime this ensures that a new instance of the D
context is created and dispos for every single request and this is important for
a few reasons like for for instance database connections are limited and they are a relatively expensive resource
so by having the DV context registered as a scov life time that ensures that
the connections are opened and closed efficiently also DB context is not threat safe so having a single instance
of the context across multiple requests would lead into concurrency issue so we don't want that we also have to think
about transactions right so having a separate DB context instance per request
makes it easier to manage transactions and ensure data consistency across a single unit of work without interference
from multiple requests and finally reusing the same D context instance
across multiple request could lead to increased memory usage because the DV context keeps track of changes to
entities over its lifetime so by having a scope lifetime that ensures that the DV context is short lift and R reducing
the memory overhead and potentially improving performance all right so now
that we understand that our gam store context is getting registered as a scope service we can start taking advantage of
it across our code base okay so let's let's go ahead and remove this line and let's put this as it was and what we can
do now is go back into our end points so end points over here games end points
all right let's collapse this and close that and
we can now go back into our post empo let's start with post this one over here which is the one
that's going to allow us to create a brand new game so as you remember the only thing that we're receiving right now in the Handler for this method is
the the dto the new game dto so now we're going to go ahead and inject the instance of gain store context that has
been registered in the service provider so for that all we have to do is just add gam store context DB context all
right so at WR time a minut court is going to take care of of resolving and providing us an instance of that context
right here without us having to do anything else and so from here on we
don't need to be creating uh these DTS manually as we're doing it here instead
what we want to do is to start creating entities into our DB context so here's what I'm going to do so I'm going to say
it's going to be just of type game equals new okay and now I'm going to do
control do here so we can import our Gam store. api. entity Nam space all right
and here is where we're going to be declaring all of the properties of our brand new game okay and let's start with
the name so name is going to be new game. name and the next one is going to
be the gener right so we want to assign a gener here now the problem is that if
we go into new game do we're going to notice that currently the gener that we
have in this new game in this D and I'm going to do F12 or here on J to see once
again the definition of our create game dto the problem that we have is that gener is just so far a string but this
is no longer going to really play well with our scenario because think about it our client is likely not going to send
us the string corresponding to the generate likely the client will will send us the ID the unique identifier of
this generate so we can create it into our data model right but so far this is just a string so we need to change our
dto at this point so that we can receive the proper ID of the
let's go ahead and change this right so let's go and do generate ID all right
and with that let's go back to games endpoints and now we can actually assign
a gener to the game now what gener will be assigned because this is this is an
actual entity right so to do that what we're going to do is just say d context
that gener that find and we're going to say new game. gender ID
right so with that we are actually taking advantage of the D context to find the instance of generate that
matches that gener and then we're going to assign that into a generate IND The Entity but also remember that we also
have a generate ID property in game itself so we should also assign this to
new game. generated right and then let's just go with the price which is you g
the price and finally the release date which is new game. relate okay so that
is the creation of our entity and then we have to go ahead and uh add this
brand new entity into our DB context and to do that we can do DB context. games the games D set and then
you can say just add and then we will put here the game right that's what you have to do to add it to the D context so
that Entity framework and the DV context can start keeping track of this brand new entity that will need to be stored
into the database another way to do this could be to just remove games and just say that add that should work too but I
prefer to use games just to be a bit more explicit to tell where exactly this game entity is going to go lastly what
you also have to do is just say DB context do save changes right save
changes is the method that's going to actually transform all of the changes that have
been tracked by Entity framework so far in this case the addition of the new entity it translates that into whatever
SQL statements needs to be executed into the database to insert the new record
into the games table in this case all right and that's really all we have to do to transform our post method into a
method that's going to actually work with our database and so let's see how this works uh in action so let's go
ahead and open our terminal I'm going to do the net run
right let's go into our games at HTTP file let me class this for a moment and
we can go ahead and create our very first game now one thing I will have to change in this post that we have here is
that as you as you know we are not sending the get gener as a string anymore we are sending the ID right so
this has to be gener ID now now what id are we going to using here well we have
to remember what id we're using uh when we create the gener so if we go back
into Data gain store context remember that here is Will we declare statically
which are the gers to be populated into the database so in this case well for Minecraft we're going to be using kids and family and this is ID number five
right ID number five over here okay so let's close this and let's go back here and let's just put number five over
here and with that we're ready to send the request so I'm going to just uh right click here I'll do send request
and as you can see we are getting a validation error which makes sense because the price cannot be more than 100 so let me actually fix that very
quickly for Minecraft it's going to be just $1 1999 let's once again right click send a request and the record has
been created right we can see that Minecraft got created over there uh it
got assigned ID number one by the database in this case ID number one and
everything is looking as it should for a brand new Minecraft game okay and of course what we want to do now is verify
that this actually exists in the database right now right which is should but let's let's confirm that so let's close this and I'm just going to stop my
my server for now contrl C to stop the server and let's go back into our SQ
Explorer let's right click on games and I'm going to say show table okay so if
we put this on the left side we're going to see that uh yep indeed our brand new game Minecraft in this case has been
created into our sqi database right so that since we working properly okay so
so that's great uh but there's one thing that is not working as it should and
perhaps we should notice that much better so let me close AQ light and uh
yeah we didn't see that but let me go ahead and rerun our server and uh just
for fun let's create micraft once again and let's see I'm going to hit send request so notice on the right side uh
that something changed here right because the response that we were sending back to the client before did
not include uh this this a composed gener object with an ID and a
name if you remember before we were returning back here for the response just generate as a string right so by
doing what we're doing here right now we have changed the contract of the response back to the client and we
should not do that right we should respect the contract we were using so far we have indeed changed the contract
for the inputs right because that makes sense right so now we have to the client has to send a general IDE and that's
fine uh but we should not be changing the contract that of the response back to the CLI so what can we do to keep the
contract as it was before right that we should understand what how to do that so let's go ahead and close this and let's
now stop our server and let's go back into games end points so really what we
should do here is instead of return if we returning if you remember we ret return in this game right here which is
the actual entity we we should really never do we should not return internal entities back to the client we should
always return our dto of data so what we're going to do is transform that game into a dto right so that that can be
returned back to the client so we're going to go over here and we're just going to say okay so gain dto equals new
and then we're just going to be filling in the properties so game that ID game
that name game that in this case generate that name
game that price and gain that release date now there's a warning here that says that hey this gener property might
be null so is that okay I mean it's a possible null reference now we know from
the fact that because we are doing over here up here remember that we are filling it it with the the right value
for the gender right and the gender must exist because if it did didn't exist we are going to get some sort of foreign
key related exception when we try to save the right so if we manage to get to this
line over here it means that we indeed have a value for had a value for Jed right so it cannot ever really be null
so we're because of that we're going to be using the null forgiving operator so this exclamation mark over there to say
hey I am telling I'm going to tell you that gener is never going to be null at this point so you will be able to access
name property just fine right and with that in place we can now return instead of the game we're going to be returning
game game dto just like that okay and so
with that change let's go ahead and rerun our server all right let's go back
to games HTTP and let's see if we can create a different game let me just grab another game here from my other screen
create a different game going to be Street Fighter 2 as you can see there we generate ID one and let's go ahead and
uh send a request and as you can see on the right side uh yep so the game got
created just fine it got a D3 which makes sense but more importantly if we
scroll down we're going to notice that the gener now is back to what it was before it's just a simple straight
that's what we're returning even when the input includes the generate ID as you can see there it's just the generate
ID but the response is z so that's the way that we can keep that contract with
the client even when our internal structure has changed right and this is why it is very important to give that
separation between DTS and the data model uh because the DTs is a contract with the client with which you must keep
at all times but the internal structure can change at any time and you want to have that flexibility all the time all
right so let's close this and let's uh stop our server now if we go back into
our code gam s points one thing that we going to notice is that ER I mean this
is this method just got too big right there's too much going on here like we have to create our entity out of the new
game create game dto and then we store it into the database and then we have to once again create a dto out of the game
entity to return it back into the client so to simplify things a little bit here
what we want to do is to have some sort of mapping logic right I mean the logic is there but we want to extract the
mapping logic into some other class that can take care of this for us so we don't have to see so much code just in this
method right so we need some refactoring here so there's a couple of things that you can do at this point I mean of
course a way to deal with this is to be is to use a mapping Library like for instance automapper is a very popular
choice to automatically map all of these fields from The Entity to the dto and to from the dto into the entity so that's
that's one possible option and if that works for you that's totally fine uh but in this case since we only have very few
properties what I'm going to do instead is a simple extension method right that is going to help us to do this in a very
explicit way and it's very easy to understand so just keep in mind that you don't need to go all the way into a
fully fledged Library just for this little mapping here I would only start thinking about such a library if the
scenario is really complex right and if I have tons and tons and tons of properties I need to map and I have
multiple entities and detos and all that maybe in that case but in this case is is very simple there's no need to
introduce something like automapper a simple extension method should be good enough so let's go ahead and open up our
Explorer here let's collapse this let's go into solution Explorer actually so so
we can go ahead and create a brand new directory uh just under gain store. API
let's right click new folder and let's name this mapping and in that mapping
directory let's right click and add a new file it's going to be a class and let's name it game game mapping all
right collapse this let's fix a name space control dot in the namespace Declaration to change Nam space to game
store. api. mapping now since this class is meant for extension methods once again we make it a static class and
we're going to create a couple of methods the first one is going to map uh create game dto instance into a game
entity instance so let's create public static it's going to return game to
entity okay so this is extending create game BTO new game all right and I guess
we can just call this one game like that okay so what should we have here so if
you go back to game end points we want to have something like this right
this logic over here so I'm going to copy this into game mapping and paste
that here now let's just scroll down a bit and what we're going to do is just
say return new game okay and let's fix things a bit here so this is going to be
just game that name now for the generate we cannot actually access the D context
from here right so we're going to keep doing that back in G endpoint so let's remove this because we are not going to be sending the into this method we only
care really about the dto okay and then for gener ID we have game that gener ID
then we have game that price and then we have game. release date all right so
that takes care of the first method and then we want to create a brand new one down here and this is other one is going
to help us map a game entity back into a game dto so public static game dto to
the so we're going to be extending game game entity right there like that now we
what are we going to return here so going back to game's endpoints we're going to be returning what we do over
here so let me copy this section down here okay and all we have to do really
here is just say return new and yeah that's pretty much it that
will return a brand new game dto so with this new extension methods ready we can
now go back into games end points and take advantage of them right so let's go back first here where we are creating
our new game instance so instead of that what we can do is say game game equals
new game. to entity just like that but uh we still have to account for the for
the generate entity that needs to be attached into the game so because of that we have to still do game. gener
equals and that's going to be this line here line 59 we have to copy over there
right there but the rest we can get rid of now so this can go away and uh one
more thing so now for the game dto we can actually just get rid of this entire section let's get rid of that and here
what we can say is at the very end and let me actually send these parameters to the next line so we can see better like
this okay instead of sending game Det we're just going to say game. 2D that's
all it is right now let's make sure that this is still working properly so let's open up our server our terminal and
let's run our server over here okay the API is running and let's see if we can create a brand new game so let's go
ahead and create a new game that I'm going to populate over here from my other screen so let me replace this with
that okay it's going to be the Final Fantasy 14 game we generate ID 2 so let's right click
let's send a request yep and as we can see on the right side it got created and
it got assigned the proper generate here this role play right it has the ID so yep the mapping is working as expected
all right let's close this perhaps let's also close this over there let's get
back to gain sence with our post and point ready uh let's move on into the
next Endo which in this case is going to be our get endo get by ID actually so
let's see what we have to do to make this endpoint is start using our DB context so of course first thing to do
is to receive the the context as a brand new parameter in the Lambda right so let's go ahead and add game store
context it's going to be our DB context right there remember that this is injected via the DI and depend injection
into our method at R time and now what we want to do is just change this line uh so that it uses the context and the
game entity instead right so for that we're going to use switch this into just
game and then here we're going to say instead of that DB context dot games.
find and here would can pass in just that ID like that so that's how you can
quickly find the entity inside the DB context now keep in mind that this find
method is going to try to find the the game within the current set of games that are in memory right now already
pulled in via the the DV context and if I cannot find them uh inside the D set the current D set in memory it will go
ahead and find it in the database if need right so it's a very efficient method now one thing that we need to
realize is that of course we don't want to just return the game right as we are doing right now like like we said we don't want to return the data model we
want to return a dto but what dto we will return if we go ahead and return like we did in post if we return with
two dto a game dto that's not going to work very well that is because let's
just go ahead and I'm going to do contrl p here to take a look at game dto so game dto here we will be returning this
and this is going to include the gener as a string however for a get by ID method we don't really want to return
the generate as a string and that is because the client would likely want to
have the generate ID to be able to use it in the UI right imagine a UI where
the user is going to be selecting a generate from some sort of drw down list right and so that draw down list will
have to match the generate ID that was returned by us but if we just keep returning the string that's going to be
just too complicated right so the string is going to go work just fine if the client is going to have a summary of all
the games right that's fine but if you want to see just one game what we really want to return back to the client is the
general ID so because of of that what we're going to do is actually to create a brand new dto that is going to have
that ID we're not going to modify this G dto but let's actually create a brand new one that we're going to name a game
details CTO that's going to have the generate ID that can be used by our brand new G ID endpoint so let's go
ahead and open up our Explorer contr shift e let's go into
DTS and actually to keep things simpler let's go back into our file explor over
here and let's uh let's just copy game d let's make a copy of this one and just
right click on DTS spacee okay because it's going to be super similar so let's name this one game details dto just like
that game details dto okay so game details dto let's rename that over here this is and like I said this is not
going to have a string gener it's going to be an INT gener ID okay so that's
game detail CTO now since we have we are renaming game detail CTO I mean we are
creating G detail dto here it would make sense to also rename this game dto to give it a more proper name right so this
is no longer going to be just game dto let's rename this one into game summary
dto right to to more clearly reflect the fact that this is a summary of the game
that includes a gener as a string and not an ID okay so this is going to be
game summary dto now of course this is going to cause a little bit of trouble so let's go back into our game mapping
and let's make a fure right so here where we have two dto this is going to do this is going to return actually a
game summary dto and let's also rename the method itself so that this is going to say two game summary D okay that's
what we should be returning from this method but also we want to here introduce a brand new mapping method to
return a game detail CTO so let me just copy this method quickly let's scroll
down and let's paste it down here let's let's change the type here into game
details dto and this is going to say to game details dto right and here of
course is going to be we're going to be returning game. generate ID all right
and with that in place let's go back into our games end points over here and we may have to fix a few things before
doing anything else so in this list this list is going to go away soon but for now just to avoid the compilation errors
let's change this into game game suto then let's scroll down over here
this is our post method map post so this should return now to game detail C right
that's what would make most sense to the client right instead of returning that
generate as a string it would make more more sense to the client to stick to just the ID right to the of the created
and generate in the game d so two game details so yes we are breaking the
contract here but let's say that we have come to an agreement with the client that this is going to be the final way
that we're going to be returning that created a game from the poll okay so game details DET now let's keep
scrolling down let's see what else we have here this should be game sumary dto
okay so that fixes all of our errors there and then one more thing that you want to keep in mind here is that since
we are going to be returning really only the details right game details dto and
which if you remember let's go back to game details dto it does not include the generate as an actual object but just
the gener ID because of that back here we no longer need to assign the gener
over here with this line here there is no need because entity framew will take care of properly assign the generate
into the game Into The Game's table he will assign the gener ID we don't need to populate that for the game entity we
were really only doing that because we needed that later on for the mapping uh but really is not needed anymore and now
let's go back to what we were actually trying to do here which is in map get get by ID what we want to do is instead
of returning results the okay with the game over there let me send this to the next line we can see better we're going
to return game do to game details D all
right and so with that in place let's go ahead and run our API is actually running already so let's stop it clean
the screen and then do run let's close this let's perhaps close this to DTS and
let's go back to games. http I'm going to put this at the start and so we are going to do just to test our
brand new method is to quer for one of the existing games so I'm going to use our second H request here to get a game
by ID I'm going to right click and I'll hit send request and as expected things
are working properly right so we are getting our 200 okay we are getting our Minecraft game here and notice that we
are getting instead of the game U the game string or the name of the of the gener we are getting the ID of the gener
here right in this case is generate ID five like I mentioned likely the client is going to use that ID five to match it
to one of the gener that it is displaying on the screen right imagine some sort of drop down so he will use
this to just select that that gener in that screen right for our user right so
that's what we're going to get in that case and it's working as a awesome so that will take care of get by
ID now let's go back into gains end points and I just stopped the server let's Now work on our put operation
let's go down here into put now of course the first thing that we should do about put here is that we need to change
our update game dto so that it can also use a generate ID and not a generate
stream so let's go back into Explorer let's go into update game dto and we're
going to be doing the same change that we did for create game d so instead of
the string here we're going to say int generate ID like that and because of
that now we have to go into our mapping to also Define some sort of a method to
do the mapping between that update game dto and the entity so let me go ahead
and actually copy the very first method let's just copy this and I'm going to just open a space here
that copy and now we're going to be mapping not create game dto but update
game dto right into the game instance now one
thing that we want to also do with update it is not just to map the update game dto but we also need to account for
the fact that this update game dto does not come with an ID right remember update game dto does not have any ID but
we do want to create this game with an ID because the user has specified that he wants wants to replace a very
specific entity with a specified ID so because of that what we can do is just to add one more parameter here that's
going to be int ID and then we'll use that ID as the ID of our return game
entity so let's assign it over here ID equals ID okay now how do we use these
two entity method back in our endpoint so let's go back into games endpoints
and here we're back in our put method okay so the first thing to do is to change this code here that is currently
looking into our old games list and we need to make it so that we find the existing so to do that all we have to do
is the following let's do bar existing game is going to be DB context and of
course we have not injected that DB context into update so let's let's make sure that we do that first so game store
context DB DB context right we have now injected that into our
maput and we can take advantage of it right so DB context dot games. find and
then it's going to receive that ID okay so now we we are finding the existing
game and if it does not exist it will just return null right we'll get a null value over here so we can do now instead
of this comparison is that we can say if a existing game is null then we going to
again just return not found so that that stays okay uh but then we got into the
interesting part right so how do we actually perform the updates well we have to do a couple of things first I
mean of course we're not going to be doing this logic anymore here there what we want to do is to locate the existing
entry inside our DB context and replace it with a brand new entity that we are
creating here so to do that we're going to do the following we're going to say DB context that entry and entry is a
method that you can use to locate the current entity inside that DB context
right so for this one what we can do is just say existing game right and for
inside that we we can say current values right so that pulls out the current values of that entity and then right
there we're going to say set values okay and with for set values we can specify the new entity that's going to replace
all of the values of the old entity so here we're going to bring in our updated
updated game but the updated game is just a dto so what we want to do is just transform this into a two entity with
the brand new extension method that we use two entity and passing in that ID
okay and that is how with this just one line we can go ahead and replace the
existing entity with a brand new entity that comes from the dto right and lastly
last thing we want to do here is to always do D context do save changes to
make sure that the changes are sent back to the database all right so that's really all we have to do for the put UT
so make sure that this is working so let's go ahead and run our
server okay I'm going to collapse this back toide HTTP so which game we are we
going to actually update right so it's a bit hard to tell right now because we have not updated our get all logic right
we cannot use this this still looking from the list so let's actually let's take a quick look uh pick into the
database to see what we have so far so Esq Explorer right click on games show
table okay so let's put this over here so we can see better okay so these are the games that we have so far so let's
say we're going to update our stct Fighter game here which has ID number three safe Fighter 2 with ID number
three so let's close this let's close that and we're going to go down here
okay I think we have most of it but we don't have the the name so let me actually complete this very quickly
with something that I have in my other screen over here and what we're really changing here is that Street Fighter 2
is not no longer going to be just a Street Fighter 2 it's going to be Street Fighter 2 turbo right turbo and the
price has changed so game was number three so let's switch it to number three
and let's go ahead and right click and execute our request so send request and we do have a problem here and that is
because we forgot one small thing which is the gener right so gener should not be like that it should be generate ID
and the ID of the generate 4 Street Fighter should should be one over there and let's right click and send a request
there you go so we got the expected 204 no content meaning that this was a success so and to confirm of course we
can go ahead and use Query for game number three by using our get by ID request over here right click Send
request and as we can see indeed we are now using c52 turbo and and the price
has changed so the update operation is working as expect awesome so now let's just close this and let's stop our
server all right and let's go back into games end points because now it is time
to change our and get all operation right so so we can actually start
quitting for all of the available games so let's go all the way up here into our
map get operation the first one that we have in our end is this one over here so how do we deal with this right so we no
longer want to use the games list but uh first thing that we have to do as usual is receive our game store context
instance here D context okay and then let me send this to the next line to see what we want to
do so of course we don't want to return games what we want to do is a following we want to say d context. games and then
from those games we want to transform each of those game instances into the corresponding game summary dtos right so
to do that we're going to do is just a projection by using the select method from Link in C so do select right so for
each game in this Games Collection we're going to say game dot to game summary
dto just like that and well technically that's all we need to return our list of
games as game suos back to decline but there are a couple of other things we want to do here the first thing that you
want to realize is that uh to games Su if I just do F12 here I'm going to do F12 to go to the definition is that um
we are going to need the generate property right here right to pull out the name of the gener and um the way it
is right now so let's go back here the way this method is right now it is going to only pull out the gains but not the
attached generat right so gener is going to come empty here so we have to do something to also include the attach
generate property for every single game and that is if we just open up a brand
new line here is this include method so include where we're going to say okay so
for each game make sure that we bring in game.get right if you don't do this then
this gener property is going to be empty it's going to be null when we pull out the games and we're not going to be able
to do the proper mapping into two game summary dto to attach the general name into the dto right so that's very
important in this case and the next thing we also want to do here is a bit of an optimization right because by
default Entity framework is going to keep track of every single entity that we're pulling out of here is going to do
change tracking for every entity and if you have many that's really wasted resources right we don't need to keep
track of anything here because we're just going to return that back into the client right away just one operation so
we're not going to be performing any updates into the return entities and because of that one of one very good
optimization I should always do in these cases is just to say say as no tracking
like this by doing that you're saying hey at the framework I don't need to do any tracking of the return entities just
send them back into the client in this case as is right so that's going to improve the oper the performance of your
operation over there okay and so yeah that's all we have to do for the get
endpoint so let's test this quickly let's do theet run all right let's go
back into G HTTP and now we can use our very first uh endpoint over there so let's right click Send request and as
you can see on the right side now we are getting the actual gains from the database this case yeah we do have
Minecraft duplicated here because of what we did initially well we're going to deal with that later but we do have out of our H I guess one two three four
games declared into the database right now okay so that is working properly and
notice that for each game we are returning the generate string and not the generate ID which is what what the
client would expect to display a summary view of all of the available right and so one more thing to
do here is to deal with the delete operation right so let's go ahead and stop our server let's go back into well
let me close this and let me close that mapping let's go back to G end points and let's go now into our delete
operation which is actually the simplest to implement so as with all the of the
other endpoints first thing to do is to introduce our game store context via
dependency injection DV context and then we have to change the way that we perform our removal of the entity so
how will we do this so couple of ways to do it but the most efficient way is to
do the following we're going to say d context. games. where and this where is
going to be so that we can select which is going to be the one entity that needs to be removed so that end is going to be
game where game. ID equals ID so that selects the game that we want to
remove and let me actually send this to the next one and then when it finds that game what we want to ask it to do is to
use to execute delete all right so this syntax here to perform the delete is is
is known as batch delete and it is a very efficient operation because we don't have to first find the entity just
to say hey framework keep track of the fact that I'm going to delete it and then go ahead and and save the deletion
so this one line here one shot is going to go straight into the database find the entity and delete it right away so
there's no need to do anything else here and then we just return no out and that's all it is okay so let's see if
this actually works so let's go back again into the terminal let's run the server back to G HTTP and so if we
remember if we right click at the very first request here we do have four games right so since we have this one
duplicated so we have Minecraft two times here let's see if we can go ahead and and uh remove the second entry of
micr ID number two right so let's close that let's go down here at the very end
and yeah our delete operation is actually looking at game number two so let's ask it to remove game number two
so let's right click let's do send request and it seems like was a success
204 no content means that it succeeded so if you go back into our list full
list of games right click here send request and let's see what happened so we have ID number one but we no longer
have ID number two as you can see there's no number two it is gone so the operation was a success awesome so let's
just close this and then uh stop our server now one more thing to do here before moving to the next topic is that
well we finally no longer need any in memory list of games right so finally we
can go back here and we can get rid of this entire uh list of games so let's go
ahead and select all of this and we can get rid of it so now it is gone okay so
with that we have completely moved into a res API that is ready to interact with
the database both for quering entities and also to create update or delete all
of these entities so that is working properly but there is one more concept that we need to also learn and apply
into a race API and that concept is the asynchronous pring mode so let's switch
a slides so we can learn more about today a synchronous programming model and why it is so
important to understand a synchronous programming let's go through a common scenario you might be familiar with
which is making breakfast let's say you start by heating your pan for a few
minutes and then when ready you fry some eggs there we would also like to have
some bread for a breakfast so after your eggs are ready we bring up the toaster
and toast our bread then then when the bread is ready we add some jam on peanut
butter on it finally our breakfast would not be complete without some juice so
let's pour in some orange juice in total it took us about 30 minutes to complete
our breakfast but is that really how you would go about preparing your breakfast
if it is a weekday when you are usually in a rush perhaps you would like to do something like this instead you start by
hitting your pan and while that happens you will also start toasting your bread and while
those two things happen perhaps you can also pour your orange juice eventually
when the pan is ready you go back to it and fry some eggs and once the bread is
toasted you go and put the jam or peanut butter on it doing things this way you
can be done in much less time say 15 minutes and perhaps you can can spend the rest of the time enjoying your
breakfast when comparing these two ways going about making your breakfast we say that the first approach is synchronous
since you won't start a new task until the previous one is complete however the
second approach is asynchronous since you don't wait for a task to be complete before starting your
next task instead you start as many tasks as you can and eventually you turn
your attention two tasks that are ready for you so you can continue with the next task in a similar way you can
perform a synchronous programming in your hnet Cod applications when a client sends a
request to the web server you want to start handing the request in your endpoint in an asynchronous way so that
your cook the Krell web server is immediately free to start handing the next request so as your endpoint starts
an asynchronous call perhaps to your DB context and the DB context in turn
requests data asynchronously from the database the web server has also started serving the next request also
asynchronously when the database eventually Returns the requested data the DB context will resume work and send
the data back to the endpoint which in turns with Source work transform
entities into dtos and sends the data back to the web server who in turn responds to the original client request
after this the application continues starting order tasks asynchronously and
resumes work whenever necessary as you can see the asynchronous programming
model brings in multiple benefits your application gets improved performance
since you avoid blocking colors and free them up to perform other tasks which
also results in overall better responsiveness you are able to escale your application better because it can
handle more requests and users simultaneously without getting bed down by waiting for Io operations to complete
and also the use of task objects in combination with async and await keywords provide a simple and intuitive
way of writing asynchronous code as opposed to having to deal with threads and callbacks directly now that you
understand the asynchronous ramming model and its benefits let's see how to put it to work in our current res API
taking advantage of the asynchronous Ring model in our net vers API is
actually very straightforward so here we're back in a games endpoints right and so we're going to see how to
introduce this autel model in each of our endpoints and let's start with our H
map G endpoint here to retrieve all of our games so the first thing that we want to do is to modify a little bit the
way that we talk to our database or to our DB context so that when we ask it to return the games it it does not just
return the games but instead of that it is going to return a task that can be awaited until the operation actually
completes that way a minut core does not have to block on the operation until it is done right so anything that goes out
of your process like going into the database going to the file system going to the network all of those operations
we want them to return just a task that can be waited and that can be resumed later on when the operation completes so
in this case really all we have to do is just to add one more call at the end here to
transform the output games into a a list in an asynchronous way so we're going to
say to list async right and so that's going to now
return as you can see it's going to return not just a list so notice this this returns okay so let's open up this
this returns not just a list but it is a task of list right so because of that
the wrong time can wait for that task and it's going to resume when the games actually come back from the database all
right and you're going to notice this convention where you use the Asing suffix this suffix over here for every
operation that is going to return not the actual object but just a a task that
includes the result of the operation right so many libraries you're going to notice that they use this convention so
prefer these asynchronous methods when you invoke these kind of apis right and you should also be using this
same convention if you write your own asynchronous methods right so that works
but the other thing that you also want to do is to use the async await combination of keywords for your own
method now in this specific method here it may not be absolutely necessary because it's just a one liner here so
arguably maybe you don't want you don't need to use that but just for convention just to keep things safe and simple to
understand let's go ahead and add async and a weight here right so we're clearly
signaling the compiler that it wants to execute this as an asynchronous operation and that it needs to await for
the task here to complete before returning the data back into the client
now we can follow this same convention across all of our methods to make sure that all of the operations work in an
asynchronous way okay so let's go down into map get to get a Again by ID and
just like with in the previous method we're going to now transform this into an async right so now it's an
asynchronous operation and we need to await every single operation that goes outside of our process right in this
case that's going to be this line here where we go ahead and find the game so we're going to say await wait all right
and so but of course find it is not an aailable method it's just a simple find method that we need to now transform
into find a sync just like that right so now just like in the previous method
iset core is going to start a task to find the game and it's going to go back to it when the game is actually
retrieved from the database let's move on into our post method now which once
again is going to be an asynchronous operation and then what is going to be the actual operation that we need to
wait for that's going to be our save changes so this is the only operation that's actually going to go outside of
the process to save the the data back into the database so we're going to say wait and this is going to be save
changes AC okay now let's keep going down into our put operation which we're also going to
turn it into an async operation like this and here we have a couple of
asynchronous operations the first one is going to be the one here to find the game this one in line 53 so this we
should await await and then find a sync right so now we can find it in a
synchronous way and then we go all the way down into save changes and again we
want to do await save changes async
finally let's go down into our delete operation which again we're going to make it a sync and then the the
operation that we want to wait here is to is to is the execute delete over here so remember that this goes straight into
the database to perform the deletion so we're going to say await and then execute delete a sync all right and well
that really takes care of all of our API endpoints now everything going on in this endpoints H class is really
asynchronous but there's one more location where we should also take advantage of the synchronous grabing
model and that is the location where we perform the migration when we start application so where is that happening
let's go back to Explorer let's collapse this and let's go
into go up data extensions under our data directory data extensions so
remember that this is the place where we eventually go ahead and just execute any pending migrations when the application
starts so this should also work in an asynchronous way right because it has to go out and talk to the database and that
could take time so what we're going to do is change this operation in a few
ways the first thing is that since we're going to be returning uh no longer just
a standard return but a task right we have to be very clear about this so it cannot longer be void it has to be a
task so that whoever calls this operation can actually await on that task now we also need to follow the
async and a weight convention right because that simplifies the way that we can deal with this task and then instead
of calling migrate we want to call migrate async okay and now our method is really
an asynchronous me but remember that I mentioned that anytime you deal with asynchronous operation you should name
your methods with an async suix so that's a convention across the entire net and C ecosystem so just like myig
async uses the async suffix over there you want to also modify your myig gr DB
method here so that it's name my grade DB a sync right just like a as a
convention and of course since we're doing this we have to now go back into program CS over here and in line 133 we
have to make it so that we take advantage of the brand new name made so my great DB async now no this is warning
here so this warning is alerting US of the fact that this method is asynchronous right because it Returns
the task but we are not waiting on it right so if it is a task we have to make sure that we actually await on it before
moving on to the next next step because of that all we have to do is just say await over there and that is going to
properly wait for the task to complete before moving on to the next thing all right and so yeah that's pretty much all
we have to do at this point to take advantage of the in programming model and what I like to do uh to make sure
that everything is working properly including this this last change is to well let's go ahead and delete the
database and let's see if when we run the application it can actually recreate a database and then we're going to start
testing our a points once again to make sure that everything is working properly with the singles grabing mode so let's go ahead and open up our Explorer let's
make sure also that yeah the server is not running right now so let's right click and delete our game store database
so delete okay the database is gone so it has to be recreated when we restart the
application so let's go ahead and open our terminal okay let's collapse this do
and run let see what happens all right apparently everything went properly the
migrations were applied as you can see here migration got applied we should be able to see the database back here so
yeah as you can see the database is back so that work just fine and then let's just go ahead and test perhaps one um
post operation here to verify that things are working properly so I'm going to right click here send request yep the
post was a success as you can see the game got created and we should be able to also query for games up here so right
click here send request yep we can query for games so things seem to be working
just just fine and now we're taking advantage of theing Prim model which makes things much more efficient for our
net R API right so let's go ahead and close this and let's stop our server
all right and get back to games endpoints that's CS at this point our games endpoints are complete and what i'
like to do now is to show you how these endpoints can be integrated into a modern web client but before we can do
that there's still one missing piece and that piece is our generous Endo because
we have the ability to fully interact with games right now but we don't have that ability with the genders and it's
not like we need an entire API and a set of endpoints for generes but we at least need the ability to be able to query
those generes because we have some UI elements in the client that are going to need to query for those gener so let's
go ahead and apply everything we learned so far about net apis to see how quickly
we can come up with a brand new endpoint to be able to query for those Jers so
let's go ahead and close all of these so let's close all these tabs let's go back to Explorer and the first thing that
we're going to need is a brand new dto which is going to be the dto that
represents the generous so let's head back into solution Explorer and let's go ahead and right
click on DTS new file remember that this is a record type and let's name this one
generate dto all right let's collapse this let's go ahead and fix our namespace install that api. dtos so
pully record class generate dto let's use the simpler syntax here to specify
an ID and a name all right so now we
have the dto let's go ahead and Define a proper mapping for Transforming Our
gener entity into gener dtos so let's go
into the mapping directory and let's actually spin up a brand new mapping class because this is going to be for
mapping generous right so let's not mix that with games so let's right click on mapping add new file going to be a class
and let's name it y mapping okay let's collapse this let's
fix a name space it's going to be G start. api. mapping and then this is
going to be a static class because it is for extension methods let's define just one method public static gener dto to
dto and then we're going to be extending the gener class which is already defined in our data model so gener and what
we're going to do here is just to return a new Genero with generate. ID and gener do
name all right so the mapping is ready and then the next step is to Well define
the actual end points to be able to query for these J right so let's go back into solution Explorer and in under our
endpoint directory let's go ahead and and create a brand new endpoints class
this time for the generous so let's right click on it end points new file going to be a class and let's name it
generous endpoints all right so here let's go ahead and also fix an name space gam
store. api. end points it's going to be a static class and let's follow the same
idea as the previous endpoints class so it's going to be a public static and we're going to be returning a route
group Builder right because we're going to be using route groups here let's let's name it map generes and points and
then let's extend our web application class app right so remember that we can
first create this map group this way so bar group equals app. map group so our
group is going to go into generous right generous and then uh
let's go ahead and Define just one one endpoint so group.
maret okay so this is going to be go just under generate so we'll just put that forward slash over there and then
for the Handler we're going to be using a syn a synchronous operation to query for those generat so it's going to be a
sync and then for the parameter for the lamb we're going to be receiving our
game store context once again install context DB context and then we have to
specify something something to do with this with this Handler right right so let's go to the
next line let's close this and here what we're going to do is just say await okay
so how do we retrieve all those gener well we use a DB context so DB context
dot generous right now if you remember here's where we have to project the
generes that are in the data model into corresponding dto and we can do that easily by just going let's go to the next line we're going to say do select
okay so for each gener we're going to do generate. Toto all right and then remember we also
said that um for this kind of operation that does not need any tracking for an
Entity framework then we just want to send back the genders directly to the client we're going to say that as no
tracking and lastly we want to make sure that this returns an async I mean returns a task as part of an Asing
operation so we're going to do two list async okay and let's actually send this
to the next line like that all right so that defines our end point and last
thing to do here is just to return our group awesome so yeah so the endpoint is
ready and last thing to do here is to actually take advantage of this method in a PR CS file so this time we're going
to just close solution Explorer let's go back to file explorer and I'm going to open up my
pram CS file over here and just under map games end points I can insert a
brand new line and let's just say app. map generous endpoints like that all
right and so yeah we're we're ready to query for those generous so let's see this in action let's do net run and what
we're going to need here is perhaps a new HTTP file so that we can add our new
request for J right so let me collapse this because we do have this gamat http but since this is different so let's
actually add a new one for gener let's just right click add the root in the file explorer new file let's name this
one generous. HTTP there and all we're going to do is just say here get and
then well we need the actual endpoint so remember that we have that here in a few places so let me copy this from our
other file there and then the pad is going to be under generate right all
right so that's it so I'm going to collapse this and let's just right click on this and let's say send request so as
you can see on the right side this was a success 200 okay and we can see down
here that we are properly returning all of our game genders so just like that we
have stand up a brand new endpoint that our client can use to get the full list of all of these genders awesome so let's
go ahead and close this and let's stop our server and and with that we're ready
to go to the last part of our tutorial which is where we're going to integrate this netr API with an actual client
application now this is totally optional because we have already done all of the backend work here and that's what we
wanted to aieve but I also like to always see how this actually serves the purpose of some client because there's
really no point of having an API if there's not going to be an actual client for this that that's a whole idea right
so I have prepared a a small client so we don't have to code this the client is ready so I'm going to open up that
client in this other vs code instance over here I named it gam store. front end this is a very simple blur
application with serers side rendering so nothing fancy really and I'm not going to go over the code of this H
front end here if you want to know more about this front end and how exactly I built it I have another video where you
can see the process from scratch how do I I created this little front end here is very simple really uh but um really
all we have to do here at this point is configure this frontend to be able to talk to our API and I have prepared a
section in abs. Json here where I all all I have to do is just to enter the URL of our backet right so what is that
URL let's go back into our other vscode instance and remember that our our URL is right here so it's Local Host 5274
I'm going to copy that and let's head back into our front end and I'm going to
paste it over here okay so now our front is ready to start talking to our back end so let's see this in action so let's
go back into our back end and let's just do run so the back end starts it's ready
let's go into our front end now let's do something similar right since this is Blazer all you have to do is just don't
it run all right so it is up and running and I'm going to go ahead and click and
this is the this is the URL of our front end right so not the the back end but the front end so I'm going to just uh
control click on that one so this opens my browser and as you can see we can already list the one game that we have
right now in our back end okay so not much going on here all is this is is
render rendering a simple table with the list of games and for each game you can see that we have uh butons for editing
the game deleting the game and there's also a Buton over here for creating a Rand so let's actually go ahead and
click on new game so to see if we can spin up a brand new game over there so notice that we have the drum down list
over here and this is the list that I was mentioning that is going to go ahead and pull the list of generes for our
game right so this is pulling from that list that we just created that back that res API for generous that's that's is
the Lisas using it right so let's go ahead and see if we can create a brand new game so let's go for let's see El
ring awesome game so it's going to be role playing the price is going to be
$49.99 and then let's go ahead and enter some date for this is going to be February 25 2022 right and then let's go
ahead and click on the save button and as you can see it went ahead and stored
our game right here okay and we can confirm that this actually talk to our API because we can go back to vs code of
course and we can take a quick look at the database over here vs SQ we can right click on games show table and we
can see that the brand new game got created over here here right so this is really talking to back to our receip
okay and so let's see how what we can do about an update operation perhaps right
and so let's see let's go ahead and update this Final Fantasy 14 game over here so I'll click on edit let's make it
so that the game is a bit pricier so let's say it's going to be $69.99 let's go ahead and save the game
save and as you can see it did save it properly without any any problems all
right awesome and then uh yeah before we try the delete let's actually come up with something something that we can
delete and we can keep the other games in there so let's just save this test game here and now I'm going to go ahead
and click on the delete button over here to see if we can delete this game and the game is gone so yeah there you go so
you have a res API that can fully integrate with a modern client like this one and I hope you enjoyed creating this
this res API with me like I said if you want to take a look at how I created this client there's another video for
that but at this point thanks for watching and I'll see you in the next video
No comments:
Post a Comment