Build a .NET 10 Web API from Scratch (Controllers, EF Core, SQL Server, DTOs)

Channel: Patrick God Published: 2025-11-13 12,540 words Source: auto_caption

Transcript

So we finally get net 10 and visual studio 2026. So this is the best time to build a new web API using controllers a service with a repository pattern and DTO's and also using entity framework with a SQL server express database. If you want to do that keep watching. We are covering everything in this tutorial here and you can even download the source code with the link in the video description below. But first watch the video until the end, learn that stuff and then check out the code.

Let's dive in. All right. First things first, what you need, of course, is the .NET 10 SDK, Visual Studio, and then already if you want to do it, download SQL Server Express and SQL Server Management Studio. It's not a must, but later you're going to use SQL Server. So, maybe you can do this now as well.

Easiest way to do that is just entering .NET 10 into Google for instance. Find the download link, click on this thing, and there it is. 11th of November it was released. So, this is currently the version I got. In your case, of course, this might be different, but for my system here, that would be 64-bit Windows.

Please download this thing and install it. And then you would probably also want to use Visual Studio 2026. The community edition is the free one. Hit download and then it will already download this thing. But of course, you can also use Visual Studio Code, Jet Brains Writer, whatever you want to use.

in particular on Mac, you wouldn't find Visual Studio anymore, right? So maybe you need something else. And then real quick, SQL Server Express is the free version I use pretty much every day for everything I'm testing. And this also works. Then if you want to deploy your web application to Azure, then it is very similar to Azure SQL. So this totally works and it's free.

Okay, so go to SQL Server downloads and then you should find this one here, SQL Server 2022 Express. So download this thing as well. And the last would be Secret Server Management Studio. It is not a must, but I like to use it because it's really easy then to change your data, see the tables. Yeah, very very nice and organized this tool.

So here, download SS SMS22. And if you got all that covered, just run Visual Studio 2026. So let's do that together now. All right, there it is. And I would say we create a new project in this new look and we want to build a web API.

So when my machine wants to, we can actually already look for web API. And there it is. Aspet Core web API is what we want to build today. So we hit next and make sure to use C# here, right? Not F# down there. Next it is.

And for this simple example, you know, maybe I like video games. So let's build a video game character API, shall we? And I want this to be placed into a different folder here like that. We hit next. And now we choose the framework. I don't know why, but in my case it still says net 10 preview but when I enter it in the terminal net- version you see it is 10.0100 100.

So that version we just downloaded together. So well let's see how this project then will look like. I haven't tested this before honestly. So let's just create this thing. We are going to use controllers because I love the traditional controllers.

So let's see. All right. Here is the solution explorer. And here now in the project file there you have it. Right.

We see target framework is net 10.0. 0 and the Microsoft APL core open API package is also 10.0.0. So I assume that this is hopefully now the version of all these packages right everything should be updated let's just move on I'd say now but what do we see here actually it is pretty straightforward in the example data we got our programs yes the entry point for everything in your net web applications and the interesting part since net 9 is this thing here add open API. So this means that we get an open API structure let's say for documentations. There it says it adds open API services related to the default document to the specified I service collection.

And here now this registers an endpoint onto the current application for resolving the open API document associated with the current application. If you don't know what this means in essence this means that you can use that JSON file. As you can see here, it is a JSON file that we get from that that can be used for a documentation of our web API. And this is what we will also do. Uh next in this tutorial here, we will add Scala.

Before we used swagger maybe you already heard that swagger UI was beautiful UI and you can still use swagger if you want to. It was there by default in net 8 but since net 9 they removed it and then it seemed scalar was the new package that won regarding the documentation so let's just use scalar it doesn't really matter what you want to use you can use scalar or swagger I want to use scalar now but there's really no no preference on my site here both are just great so yeah this is something we should do but you can also use if you want to these http files right so this is 1D default endpoint here you see and you can actually hit send request inside Visual Studio and as you can see it is awaiting a response not working right now because the app is not running of course so no connection could be made because the target machine actively refused it which is a mean message it just means that the app is not running but if you run it you see something happened right and we should get another terminal window there it was okay and as you can see here now we have these uh URLs let's say now for our application an HTTP one and an HTTPS one and now if we hit send request again then we see that we actually get a result here right so these are now our demo weather forecasts I know beginner stuff but I want to reach everyone here so feel free to skip through the video we will get to the meat in a couple of minutes by the way we are currently running our net 10 fail at the .NET Web Academy. So, if you're tired of jumping between tutorials and really want to master fullstack web development with .NET and Blazer, check out the link in the video description below. Now, how's this generated? Well, we have first this weather forecast model here with a date, a temperature in Celsius, and in Fahrenheit, and the summary, and then the last thing, this controller here. Right? And this is already pretty interesting because we have some attributes here.

So for instance, API controller indicates that a type and all drive types are used to serve HTTP API responses, right? So if you are making a web service call, what you're doing every single day when you're surfing the web, then you would grab some data, fetch some data from a database for instance, right? Or you post data. So you create something or you update stuff. This is all done with an HTTP API request. And for that we also have request methods like get, put, post and delete. We will use all of them and then I will explain them.

And route here in this case just means that well this specifies an attribute route on a controller. And this convention here in the brackets means this is the name of the controller. Right? So when we enter this name here additionally to our URL then where is it? There it is. Then we would get this stuff here right the the result. So here you see video game character API host address which is this thing here the HTTP one not the HTTPS one doesn't really matter for this example.

And then you see here they added weather forecast. Right? So exactly that what you see here the term before controller is used and then it says this is the HTTP request method which is get this means I just want to receive data I don't want to send a body nothing there's nothing there that I would want to send there and then store in a database for instance so for that we're using a get request and this is exactly what we see here as well right we use the HTTP at attribute. We can give this a name if you want to, but you don't have to. And then we have the actual method. The fun part is now that we still have some conventions here.

So if I just comment this out, restart the application should still work because the method here is called get, right? If I also would call it get weather forecast, it should still work. So let's just try this one one more time. And yeah, this was pretty fast. So you see this still works and uh we get this bag a 200 okay status code and this is something you don't see here but what we could also do is instead of return uh all that stuff here we just say v result is this. All right now we get this error message that nothing is returned.

We can then return the result and automatically talking about conventions, right? Uh it will also return a status code 200 meaning that everything is fine or we just say okay and then the result like that. But then we have to change the return type to action result like that. Maybe even use the interface in this case and then put the type in there and then like that not the interface like that and then everything should be fine right we have no error message here so we can now restart the application again and here this method tells you it is returning status code 200 okay and let's just try that one more time send the request 200 okay is there but we could also use an error message for instance like bad request Right? For whatever reason, we entered something that is not correct. For instance, if you're looking for a certain ID, then we can use a not found error like this one here. We say not found.

Okay, you see there it returns a status 404 not found response. And the bad request usually is something with 400 400 bad request. And there are even more for that. just for testing this. Now, let's say we return the actual result but with an error status code.

You can do everything there. Send the request and you see we have 400 bad requests but still get the data, right? But you could also add error messages there and so on. So, let's keep it as that I would say and [clears throat] maybe even use the attribute because I mean why not? Now the another or the next step that I suggest is before we add scala actually pushing everything to source control. You want the the source code right? So I would have to add this to source control. We can do this on the bottom right here.

We open git in my system. Everything is already connected to git and to my account. So as you can see here I have this account. This is the owner and the repository name now is also video game character API. Again, you can download the source code below with the link in the video description.

And let me also push this real quick. All right. And now before we implement the actual video game character API, I told you I want to have Scala in here. So, as you can see, we have the uh open API stuff already covered, but I want to have a beautiful UI where I test this and not use this HTTP file because well, I'm not the biggest fan of it. So let's say we want to have a beautiful UI.

So in that case we right click our project manage new get packages. Could also use the CLI of course. But now here we browse for Scala. Scala Easpet core. You see 9 million downloads.

This is huge. A year before it was like I don't know 10K something like that. And now it's 9 million. This is just crazy. Okay.

And as you can see here, it says generate beautiful interactive API documentation from open API specer document. So let's install this real quick. And then we go back to our program CS. And now here we just add app map scala API reference. Maybe I should have added the using directive first.

But with control period, yep, there it is. Using Scala ASP net core, we can restart the application again. We see it here. So let's go there. And then this looks like that.

Not very satisfying, right? But we can enter scalar. And there it is. This is now the UI. And here you see our get call. We can also test the request here.

And hit send. And there is our data. Beautiful. All right. So this works.

We can leave that open actually. And now focus on our video game character API. All right. And now the first thing I would like to do is add our model. Right? For that I create a new folder and just call this models for instance.

And then in there we add a new item and call this character CS. Now this should be pretty simple. This is already a good suggestion. An ID. We could use a GUID or an integer.

To keep things simple, we can use this integer here. Then we got a name which I also like. And then I would okay like to add a game. Now this is co-pilot in action. I promise you I did not do this before.

So it's crazy that it just assumes that. And this is not what I wanted. I wanted to add a role there. So for instance, a character could be a hero or a villain, something like that, right? Nothing to do with authentication here. I got other tutorials about that.

But this would be our simple game character. And this is also our model that we later will see as a table in our database. But maybe this is too much at the beginning. So here we have our model first. And already what I would like to do is return some mock characters.

Let's say from a new controller. I know in the beginning I also told you something about the repository pattern and the service. We will come to that. But let's do everything one step after another. All right.

So add a new controller. We save that and right click the controllers folder. And then here we can say add controller. Now we got a bunch of options. We have this MVC controller, but we're not using MVC here.

We kind of use the MVC pattern, model view controller pattern, right? Where we have a model and a controller and the controller then changes the model, updates the the model and with that then the view. If you would have a front end for instance, then the view would also change. But this is something different here, right? This is not an MVC application. This is a web API. And here now we have the options to add controllers.

An empty one, one with read write actions already, even with entity framework. So we could actually already let create everything we need here. But again, you're here to learn something. So I suggest really start with the empty one. And when you then know that you can do other stuff, right? So let's add the empty controller and we give it of course a name like video games or game character controller or characters.

This is actually up to you. Let's add this. Okay. Again we already talked about the attributes. We have the route and the API controller.

Now switch. Why not? And you see that by default now not like in the weather forecast example, right? we have API the hard-coded text and then the controller name again. So this would be then API video game characters and then we get into the controller and then with the help of the attributes and the HTTP request method we can now decide what do we actually want to see there right or which method do we want to call now in this first example I just want to receive a list of video game characters I already have that suggestion here it is going to be an HTTP get method and I also already want to use an async method and this is beautiful here copilot that you are suggesting to get this method this is actually everything I want but let's change this a little bit so it is public but it is an async method in my case so async task is what it's going to return and in there now I want to return an action result and by the way here you saw why the interface did not work before in this case now if you don't enter anything in there then it works. So if you don't set a specific type here then this works right when we commit this or commit when we uh apply this whole method then you see this works. But when I now say I want to return a list of the character model here in this case and we add the reference then you see we still have this little error message here right but if I now say this is an action result it is gone and this thing here is just telling me that there's a syntax error and this is actually correct.

Nope. Now it works. Yeah, I forgot the the uh the bracket there. Okay. Anyways, and yeah, this is what just for information.

This is why it did not work before. But um I want to actually define that precisely, right? It helps our documentation tools to see what are we actually expecting from this method, right? So task action result and then a list of characters is what we want here. And since in this particular example I want to use a static list. I would like to do this a bit differently. Static list of uh characters like that.

Right? We call this also characters. And yes, this is a new list, but we also already implement some characters. And actually, I want to have different characters here. So, that would be a new character. And Mario's great.

Super Mario Brothers is also great. But for me, this is a hero. Like that. Now, it's getting complicated. Something like that.

All right. So, we have Link is actually also great. Legend of Zelda. Yes. But here now, let's use Bowser from Super Mario Brothers.

And this guy is a villain with the ID three. And that's that. So here now, we could just return the characters like that. Or if you want to just use one line and no curly braces then we just say await task from result okay characters. If I would just return something like that doesn't work.

Why not? It says okay object result doesn't contain a definition for get a waiter. This is because of the async method. Now why did I already use async here? Although there's not really an async operation. Well, we could change the code later, but this is tedious work actually and later we are going to use a service and then also entity framework there. So this is everything or we will then use asynchronous methods with that.

So we already got this one covered here. Okay. Now this is the controller and please don't get me wrong, you wouldn't do that in production. Of course, you would use real data somewhere else. You wouldn't use a static list here uh for your characters, right? This is not the best way definitely.

And we would also probably use a repository or a service and we will do that as well. So, let's just save that again. I want to do that one step after another. So, it should be rebuilt now. Uh let's check out Scala here.

We have to reload this manually. And now here we see video game characters. This is nice because it groups also uh the controllers, right? We have the weather forecast controller here and then the video game characters controller with the get method here already. And you can see it expects a 200. Okay.

And here also a resulting schema or a demo schema. Right? So this is what we get. We test the request. We hit send. And there's our data.

Isn't that nice? All right. So this is the controller real quick in general. But before doing all the work now in the controller, I suggest we make this a bit more clean. And with that I mean we are going to use a repository and a repository is nothing else than a service in essence, right? So using dependency injection there meaning that we will inject this service into the controller and when the user is asking for the characters it will use the service to get these characters right so let's do that next we create a new folder and this is the services folder in there since we want to use dependency injection meaning we can inject this thing we don't create a new inst instance manually we will inject it with the help of the constructor and we can also register it in the program CS so it is available in a certain way this is why we're going to use it and in particular later if you want to write unit tests or test your services if you're using dependency injection with an interface you can mock them easily all right so I know maybe too many terms that you uh don't know what the the terms mean But um you will again get the idea throughout this course here. So let's add uh a new item.

In that case that would be the I video game character service name. Actually maybe I should just name it I character service. But I think you get the idea. And then we create a video game character service which is the implementation file but we want to use the I video game character service. So this means with this interface here we know it's like a contract right we know the following methods that are defined in that interface have to be implemented in our implementation uh class the video game character service in this case.

And to make this work again we have to register this thing here. And how would you do that? Well, similar to actually all the other methods here it says add controllers add open API. But here copilot already suggests exactly what I want builder services add scoped and then the I video game character service and the video game character service is the corresponding implementation file. Now this means whenever doesn't matter what it is but whenever something wants to inject the I video game character service then it will automatically get the video game character service implementation. If we would have another file here like a video game character service 2 for instance and then we say here all right whenever someone is asking for the I video game character service then please give them the video game character service too in that case this is amazing if you want to test something if you want to exchange the implementation classes without removing one right so this totally works and again for testing purposes this is also great because you can definitely mock your service, meaning that you have some kind of dummy service implementation that you can use for your unit tests.

So that's why dependency injection is pretty great. And regarding add scoped, we also have other options here. For instance, add transient which says adds a transient service. Come on, give me the tool tip transient service of the type specified. And then also come on add singleton.

Right now the tool tip doesn't really help here but what this means in essence and why add scoped is used most of the time is just that when a scoped service or a service is registered at scope this means this thing lives throughout the whole request. So if we now want to have characters from the video game character service with that request, this instance of the service then lives until it returns the final result, right? And then it's gone. Okay, with a singleton, it would live as long as our application is running. It is registered once and then whenever we request something and we want something from a singleton service, then the singleton service is already there. there's no new instance that will be created.

And transient means for instance if we would ask for the video game character service and it is registered as transient service and it would only exist in the controller here for instance then it's not different to the scope service. If we would have to go even deeper, call other services for instance and these services then again need the video game character service then with every situation where we need something from the video game character service a new instance would be created. Right? So this thing then don't or doesn't live throughout the whole request. It lives through this whole little nugget where you actually need it. And that's why most of the time you need a scoped service because you have your request, you have the service, you create it, you do whatever you want to do there and then return the data you want to have returned.

And also regarding memory, most of the time it's the best fit, right? Regarding transient and singleton, you really have to pay attention there. But anyways, this is really really deep and uh the video game service in this way is totally sufficient for our case here. Now what do we actually want? I told you or you read in the title that we want to implement crutch meaning create, read, update and delete. So everything you want to do with um an entity in such a web API service for instance. Now we have in the games controller we only have the get which is also covering the read operation of crut and we also only get here all the characters.

You would also have a method to get a single character by the ID for instance and then we would also have the create the update and the delete. For that let's just add all these methods here in our interface. So again it is returning a task and the first one was a list of character right let's just add the model here. Let's call this now get all characters or get all yeah get all characters async like that. Then a single one.

So task list in this case just the character get character by ID async. Then we want to create a character or add one. So task and then yeah what should we return? We could return the character again that we just created. So character and then add character async. And you see I have this pattern here that I always add the uh character name.

But we could also just leave that out and say add charact async get async and so on. I don't know why it's suggesting here now to get the character ID. We already got this. So the next one would be the update method which could just return a bool and telling us that way did it uh work or did it not work. So update character async for instance and then also task bool and then delete character async.

You see it's a bit repetitive right and we're not returning a book we're returning a bool. A bit repetitive with the character name. So again totally up to you. Just make sure that you stick to one style or one guideline, right? Whatever you're going to build with your team or by yourself, make sure to or that most of the time the the patterns are the same. Now, of course, we also need parameters here.

Now, get all characters async is pretty obvious maybe. Now, get all characters async means we want to get all the characters. There's no filter there. But get by ID. Well, this thing needs an ID as parameter.

And then here, add character async would then grab a an actual character object. So, let's call this character and then maybe also character here. Update is again debatable. You could just send the character there or also the ID of the character, right? And then double check uh is this actually correct? Does this ID exist? and deleting this is true. We just add the ID here again.

Okay, so these are all the methods for all our crowd operations. When we now go to the implementation, we already see the arrow here that we should definitely implement something and with control period or this little thing here, we can say okay implement the interface for me and it is doing that but throwing not implemented exception everywhere. All right. And this is totally fine because now we can start implementing that. And I would say we start again with getting all the characters.

And for that we just move our logic somehow from the video game characters controller to our service. So here now the list can be moved to our uh video game character service. And again if you're wondering yes this is still not realistic. This is still not something for production that we have this static list here. we would definitely use something from a database but again I want to teach you that step by step so let's keep using the static list here for one or two operations and then we move on using entity framework with a SQL server database so that's that and then here now we uh no let's go to the service first and here now we want to return uh our characters right so we can actually again grab this and then here we say get all characters async, right? Like that we say this is an async method and we just return the list of our characters like that.

We save this. I don't know what this is but uh this should work but we have to change our controller now for that. This means told you already we need to inject the video game character service. Now there are two ways to do that. You could actually use a constructor here.

This is let's say the older way but with C 13 we got the primary constructor. And this means we can inject it right here in this first line where we also define the class. So here now we say video game characters controller and then I video game character service and we call this service like that and it says now this thing is never used right but we want to use it now down here in this particular um method and now maybe things already come together. We return okay for status code 200 and then say await service get all characters async. You see now we are officially using an async method there.

Now of course we are not really using something asynchronous here right but still task result works as well. So now here we have to save something. Here we have to save something. Let's just save everything again. And now we have already the way from our controller to the service.

The service is grabbing the list here and then returning everything hopefully. So let's just restart the application and the result should be the same, but our code is a lot cleaner. All right, there we are. Let's reload Scala again. There's the video game characters.

Test the request. We hit send and we get our characters. So, let's just double check and change or add one more character with ID 4, for instance. This is now Zelda from the Legend of Zelda, and she's a princess, of course. So, let's restart the app, reload Scala, test the request, hit send, and there's our princess.

Amazing. So, this works. And now let's implement just one more method in this uh scenario where we have the static list and then move on to entity framework and that would be getting a character by its id. So here now this thing is also async and here we have the ID now right as a parameter. So we can search the character in our list by its ID.

So we just say bar result or character or C whatever you want to use here our characters and actually we already got the suggestion here which is just I actually love that but still you really should care about the foundations and learn what this is actually doing here but yeah this is correct we want a character using this method here first or default where the C which stands for the character then so we're using the character here every single character of our list and we check if the ID of the current character from that list that is first default going through if this equals the provided ID here. All right. And if we got one, we return the result. Now here could be the case that this is null. So let's just say we add our question mark here and also to the interface and then in the control uh in the yeah in the controller we are testing for exactly that.

So here we could now also say this is what I actually wanted. Yep, this thing could be null. We say that with the question mark here. And now when we go back to the implementation we should not have the warning. Yep, now it's gone.

All right, this is what I was expecting. And now let's move on to the controller. And here we want to have another method. And now it's getting tricky because we also have a get method here. But copilot is already suggesting the right thing.

We have a parameter and we can define the parameter exactly like that. So this is the so-called attribute routing and with curly braces we now say okay this is a parameter and I need or I want this parameter here in that endpoint. Okay, we could also give this a name like get uh get a video game character by ID, but I think in this case this doesn't really make sense. Then slash and then the ID and then this would be the route for this endpoint for this specific method of the controller. But get is sufficient with an ID.

Now this means that we would use API, right? API then the controller name and then after another slash the ID. All right. Now, Copilot, are you suggesting something? No, not yet. But this is also a public async method with a task returning action result one character correct get character int ID and I think it's already doing the correct thing because it says var character is await service get character by ID async with the provided ID and this is exactly what I wanted to do. If the character now is null because it could be the case that the ID does not exist then we return null.

We can also add an error message here like character with the given ID was not found but otherwise we return okay character. Now this thing here could be also written in just one line. So here we could say return result is null uh result character actually let's character is null then in that case we return exactly not found with character with a given ID was not found and then otherwise if it was found we return okay with the character again I leave this up to you all right this is really really really uh Well, matter of taste, preference, coding guidelines in your team, whatever you want. I'm often uh let's say guy that likes traditional syntax where the same with controllers because we also have minimal APIs, right? I like when we have a couple more lines sometimes, but it's easier to read, I think, for me. But I don't know, I'm almost 40 now.

You know how old I am. Um but here in this case it can be hard to read sometimes right even or in particular with that um with that error message if you would leave out the error message then maybe it's easier to read. Okay, but again this is totally up to you. the other case now or the other version where we just have the if and then in the next line we say okay what's happening when this case is true and what is then happening if this case is not true maybe I don't know because it's a bit narrower you tell me tell me in the comments would be really interesting to see what do you think is better this oneliner or would you rather use more lines of code anyways the result is the same so let's restart the application and see okay there we are yep two methods now When we test that again we get all four. And now here we say see that ID is required.

When I enter one I get Mario. Four is Zelda. What about five character with a given ID was not found. And status code 404 not found. Amazing.

So this works. This is great. I haven't committed anything lately. So let's commit this and then we jump to entity framework because I think it is not necessary to show you the whole implementation and then kind of throw it away in that particular case right I am uh diving deeper and you have you see more detail in the domain web academy there but I think for this tutorial now this is totally sufficient and uh yeah let's commit this and then move on with entity framework all right so entity framework before we can start implementing anything we need new packages, right? We already downloaded and installed SQL Server Express and SQL Server Management Studio, right? You watched the beginning of the video, I hope. If not, just go back, install it, and then come back here.

I can wait. Actually, I can really wait. And now manage nut packages. And here now that would be like entity framework first and we get this thing. Not this one here.

Not entity framework 6. EF6. We want this one. Microsoft Entity Framework Core version 10.0.0. Brand new stuff.

This gives us uh as it says here, modern object database mappa fornet. It supports link queries, change tracking, updates, and schema migrations, effort, and so on. The best OM in my opinion when you're working with.net. So, let's install this thing. And ORM in essence means that it will map your classes with the database tables.

And you will see that in a couple of minutes. But this is not everything. We also want to have the tools. Question is, do we see them here already? Nope. So let's look for the tools as well.

There they are. Entity framework core tools for the uh for the NG get package manager console in Visual Studio. So this means it says here actually what we can do with that right we can add migrations we can update the database we can do a whole lot of stuff give us a script even if you want to for instance create the whole database uh on another database this is something you could for instance do if you publish your app to Azure and then you need a database on Azure then you can say okay give me a complete SQL script from our application run it once and then you get your database case there. It's pretty neat. So, install this thing and what's uh migration and all that stuff.

You will see this in a minute. There's just one more package I want to add here and this is this thing entity framework SQL server. There it is. Entity framework core SQL server Microsoft SQL Server database provider for entity framework course. So, this is the provider you need if you want to use a SQL server database, right? If you want to use another database like SQL light then there is a provider for that or Oracle MySQL Mariab whatever it is right there should be a provider for that.

So yeah hopefully everything is installed now and when this is done we can create our database context for that we create another folder new folder we say data for instance and in here now we add a new item and by default this thing is called the app or application DB context. You could call this now the video game characters DB context whatever you want. I think if you call it context people know what you mean and we are actually deriving this time from DB context. Okay. And here you already see the suggestion it is using or we want to use Microsoft entity framework core here.

All right. And again we can actually use the primary constructor here. So what do we need? We need DB context options. So DB context options it is with our app DB context almost. So this is a bit too much of suggestions here.

And uh this thing is simply called options. So that should be it. All right. And then here we also use the options. Okay.

Now what is this thing doing as you might see here? Yep. The options to be used by a DB context, you normally override on configuring or use uh a DB context options builder to create instances of this class. And it is not designed to be directly constructed in your application code. Now you know and here we already have a beautiful suggestion. Well almost we want to use our video game characters and initialize this with a character set.

So what is this? This line is very very important. A DB set. This thing says can be used to query and save instances of character. Link queries against a DB set will be translated into queries against the database. So link now language integrated query.

This means we have a syntax and functions in particular that we can use to query our data. So we can get our characters, we can add a new character to our characters in the database and so on. And this is the DB set. In essence, you can just store in your mind that a DB set is nothing else than a table in your database. And characters is the name of the table.

And if you say you have a character model singular, then you would say the plural of that characters would be then the name of that table. All right? And this is everything you have to do here. So you have your context this is defined you have the characters table and then you also have to register this thing in your program CS could be the case that copilot is suggesting that here as well so let's say yeah maybe here we say builder services and then add db context nope we have the app DB context okay with options this is correct and it is now suggesting use SQL server. We add the uh using directive here. Then it says build a configuration get connection string string default connection.

This is totally fine. Uh you could add the connection string here. So the connection string is that thing that is necessary uh for our app to know or for framework to know where's the database. Tell me I don't know. You say me tell me where where the database is.

And you could then put it here or typically and this is definitely the better option is you have your app settings JSON here and then you say connection strings and then here you say default connection. But this is not the connection string I want to use. I want to use a different one like that. And this is not the best time to add some errors or typos here. But let's just try it.

So that should be server and then again SQL server express installed locally. So that'll be localhost SQL Express. All right. Semicolon. Then we have Okay, now it's already suggesting something.

Come on. Let's let's just use that. So we have the database which is in the video game characters database. Trusted connection is set to true. But this is not everything.

We also have to add trust almost trust server certificate cert yep and set this to true as well. So hopefully no typo anymore. This should be the connection string. There it is. Server equals localhost back slashbacks slash secret express database is video game characters database trusted connection set to true and trust server certificate also true.

All right. So this is our connection string and again in the program CS this is how we get this connection string entity framework is installed and configured and the next part would be to add the migrations. So let's do that after committing this here. All right for that we open the package manager console. You can find it here actually video uh view video view other windows and then package manager console.

And here now you have to be in the right directory. So CD video game and so on. And then we say add migration and then just initial. So this means it would create a migration file that defines our characters table. And uh there is so you would see it here in the solution explorer.

There's a new migrations folder with an internal snapshot. This is something for entity framework. And this thing here, this initial file now, initial migrations file is what we can have a look at. So let me just check real quick. We have an up method and a down method.

And you can see the up method is pretty simple. So it would create a table with the characters name and then also adds the uh columns and it already knows that ID is an identity field. So it will increment the ID automatically and it sets the primary key of the characters table to ID. And we can also roll back a migration in that case it would run the down method and that would just drop the table. Looks good to me.

So now we can run update database. I know updating is or the term update is confusing but you know we are all developers we are lazy so they just called it update even if the database does not exist it will create it then it's it's smart enough in essence okay you see what it did created the table right and so on and now we can open SQL Server Management Studio and check if the table and database is really there okay I got a bunch of uh databases here mainly from the academy and other tutorials. But here is our video game characters database. You see it here with the uh characters table and the corresponding columns. We can hit edit.

And there we see that we see no characters. So I would say we we should create them, right? But maybe we can put some in there manually and then uh first get them from the database. All right. So for that we go back to our service and now I can already hear the debate in the comment section. Why use a repository here? Entity framework actually already is a repository or already uses a the repository pattern.

And yes this is true. You could do it differently. Again this is totally up to you. We could also say we put all our logic into the controller. Still, I like it that way.

I like it to teach that way because then you can decide for yourself then later what is the best way for you. In this case, I'd say keep the controller as thin and stupid as possible. Have your logic inside your service in that particular case and just use the other repository. So, one repository then in this case is calling another repository. In our case, then the service would call the entity framework context or the database context.

I'm fine with that. Is in my opinion, it's still clean code, but I know you tell me in the comment section. Can't wait to read every single comment. All right. So, we have our static list here, which we actually don't want anymore, right? So, now we want to get uh the data from our from our database.

And again, we can use primary constructor here. And similarly to the controller, we can now inject the DB context. So here now this would actually be the app DB context. And we also call this a context. And we're done.

This is everything. And this means now that it is going to inject the context our app DB cont. Here cop is still suggesting the other way from before or let's say if you don't want to use a primary constructor you would first say private read only appd context context and then in the constructor you say give me the context injected and then you would inject it and you have this little uh guideline here or style styling you you know what I mean uh when you have this underscore before the context name which is actually pretty nice because with that you see okay this is a private read only field right again up to you what you want to do here you could also call it that right would also work so you tell me what the better option is now regarding our methods here we have get all characters async and what we can do now here is instead of that list we say give me now the uh context And then here we have now the characters available our DB set right and from that we can just say to list async all right like that and that's it and similarly here now we can actually say exactly we want from the context the characters where and this is now another method we got find async and then the one with the given ID and it says here already finds an entity with a given primary key values. If an entity with a given primary key values is being tracked by the context, then it is returned immediately without making a request to database. So if it is already available somehow, right? Otherwise, it would make a request.

Otherwise, a query is made to the database for an entity with the given primary key values and this entity if found is attached to the context and returned. If not, if no entity is found, then null is returned. So in essence, the same stuff we had already. So, we do not have to change our controller. See, isn't that nice, right? We change one part of our code and since we're using a clean structure, we don't have to change another part of our code.

I love that. This is this is fun [laughter] in my opinion. This is how web development, software development, coding, you name it, uh is lots and lots of fun. So, yeah, here's our video game controller. Again, nothing has to be changed here.

And, uh, I'd say, wait a sec. This is grayed out. Grayed out is grayed out. The you know what I mean? We don't see it anymore. We don't need it anymore because we're actually not using it anymore.

So what would we expect now when we test this? Exactly. We wouldn't get any character because in our database there is no character. So let's open Scala real quick. Reload. And here now we test the request.

We hit send. Nothing there. Okay. Empty list. Right.

Works for me. And now again regarding this thing even if we enter just one we say character with a given ID was not found. So let's add some. So here now in visual uh not in visual in secret server mention studio we can make this a bit bigger. All right.

And then here say Mario Super Mario Brothers he is a hero. Then we say Bowser from Super Mario. Wait, we should do this probably, right? So, this one is a villain. And then we have Link from The Legend of Zelda, who is also a hero. Let's keep it at that.

You see the app is still running, right? Did not uh reload it or anything. And now we can go here, test the request, hit send, and we're getting our characters. Isn't that nice? So yeah, we got Mario and so on. And now with uh getting a single character, we can actually send this again and we get Mario here. And this is no character.

Perfect. So we already have our whole setup. But there's still one more thing. And of course, we're also implementing the other methods. But first one thing for an even cleaner code let's say is what I don't like here is we are actually in our uh controller it is we are using our entity model and this is not how you should do it.

What you want to do is using a DTO a data transfer object. I also made a video about that. Maybe you want to check it out because with that you can define how this object should actually look like, right? You can have a request object, you can have a response object, meaning I have a specific object that I want to send to the service or to the web API and a specific um model, a specific object that I expect back. Now, returning characters. Well, yeah, this looks pretty much the same as the actual uh model here.

Still, let's create a new folder real quick. Add a new folder. It is call this DTO's maybe. And then regarding the naming, this is again totally up to you. We can call this get character DTO.

We can call this character response DTO. Totally up to you. All right. So or only response you name it. Let's call this now get character or actually I like get character response.

So I know the action is actually getting a character and this is in the response. Although if you want to use it in more methods then maybe we just call it character response and this also works right because the thing is now and let's just do this in theory otherwise this tutorial it's already blown up. I'm recording for 1 hour. So uh I think yeah we should slowly come to an end but we have a couple of methods to implement anyways. So the character response now why that let's just say in our character model the actual entity that you would also see in the database right here we have I don't know copilot is suggesting a description why not let's add a description there but also what you typically do right in a real world application what you guys always want to see is something like dates created at updated at deleted at right maybe a delete flag and so on so you want to store this data in the database but this is nothing or not always you want to see that also in your front end right so the object that you're going to return does not include this data right so let's say I know we copy this now but let's say this is just an example and uh bear with me here I think you can uh in the character response now we add this all right and I don't know just for for learning purposes let's say we remove the ID I'm not interested in the ID I just want to see the name the game and the role it's nice that this rhymes the name of the game.

Okay. And now when we go to our controller, when I find it here, what we now can do is we say, you know, actually I don't want to return a character here. I actually want to return a character DTO. So the response object character response, right? And this is funny that this happens actually pretty nice for for learning because now you see that copilot is suggesting to map the the uh character object that we get from the service to a character response. So we would have this mapping logic inside the controller.

But I would still like to keep the controller as thin as possible. So I wouldn't do it here. where I would do it is actually in the service, right? So, both methods now return a character response. Interesting that it doesn't Yeah. Okay.

I I know what's happening here. Actually, it doesn't really matter what you put in here. It would still work. Uh more importantly is this thing here, the action result, right? This is indeed not that important. But anyways, when we check out this method now, right, it returns a character here.

So let's change these. We here now say these return a character uh come on character response right we will change these two here as well in a minute. So that's that and now we of course have to change the the service for that now because now we get the error here. I wouldn't suggest or recommend hitting implement interface because with that you get new methods down here you see. So remove that.

Uh but what we have to do now here is change these methods. And it is actually already doing that. And this is something that I really like. So I hope I did not destroy something here now. So we get a list of character response.

Yeah, this is just the uh using directive that's missing here. And what this thing is now doing, again the syntax, well up to you. Maybe we do it that way here, but give me a sec. What this thing is now doing is it uses the select method here of link and there you see it projects each element of a sequence into a new form. So it goes through the whole list grabs every single character and creates a new character response object then and maps this stuff manually.

There are other options to do that like using mapar or automapper. again did a bunch of videos about that and in the web academy we do that as well but let's say in more detail and more structured maybe because we're building complete big projects there and then it says to list async this works and then let's say here as well we want to use the uh character response now copilot are you giving me something no in that case it is not so here now we can do the mapping manually but maybe not that way with the find async method. Now what we can do is actually this is going to be a bit more. We say where this is the ID and then we select this and now it's giving me the uh suggestion to create a new character response and from that there's one more thing we can say first or default async. All right like that and let's see if this works.

So let's restart the application. Have a build error. Yeah, I wanted to restart the application. Still saying me that something is not correct here. Doesn't implement interface in member.

Ah, I forgot one. Which did I forget? Come on, go away. Yeah, this one here. That's true. Okay, now it should work.

We hit reload. Let's first get all the characters. And there you have it. No ID anymore, right? Okay. And now here test it with ID one says that and five character with the given ID was not found.

All right. So this works. I think we now have all the foundations. I will commit this and then we cover the other methods like adding, deleting and updating. All right.

Now let's just do everything at once and maybe we can start with the controller because this is um I don't know if this is the easier part but then this is done and uh we don't have to really change something in the service already because the methods are already there so we can just use them. Next. Yep. Updating please. So HTTP post is the HTTP request method if you want to create something add something and this means that usually in your body of your request you would have in this particular case the video game character and for that I would also create a DTO.

So let's do that real quick. So here now in our details folder we add a new item and now again we have the character response but what we could do now is something like create character request right or character requ character create request or since I'm really lazy today let's say create update character request although no let's let's do it the right way let's just say we have the create character request request which is just then the name the game and the role and in the update character request object then we also add the ID. So let's put that here and let's copy. Yes, nice. So here we got the name game and roll.

Let me just copy that real quick. And here now we add a new item update character request. All right. Again is it suggesting something? Yeah, almost. But please also give me the ID public int.

Yes. All right. Nice. So with that we have our uh our DTOS ready. Do you by the way do you hear my my stomach? I I didn't have breakfast today and it's almost 12:00.

So yeah it's not healthy. Don't do it like me guys and girls. Don't do it. Just coffee. Coffee is the only thing I got today.

All right. Anyways um we go back to the controller now. And here now we say public async task and it's suggesting action result character response add character character almost right let's just say we want to use the create character request here we can call this character or we call this um a request this is again up to you then we got the created character service add character async and you see we have to change something here still uh the uh DTO objects of the DTO's DTO's not the DTO you get the idea created at action yes this is the default stuff right uh that we tell then there was a new entity created with this given ID actually here this should be the ID and not the name and this is then the created character now let's real quick you see now we have to jump around a little this is our create character request object object and here it is the update character request object. We go here and also add the update character request and now here add character request. Nope create not add.

See so much to guidelines style and so on. So maybe we should call this create as well. All right, please please accept my apologies for that. Anyways, we got this now covered. So now back to the controller and this should actually be it already.

And don't know what this is here. Oh yeah, of course we have the character response. Okay, this was this was just for uh uh learning purposes, right? Let's comment this comment this back in. And then in the um where is it now? In the controller, this should actually be gone, I would hope. Yeah, now it's gone.

And then here in the implementations, let's also set the ID like that. And same thing here with the comma, please. Okay, this is done. And now back to the controller. Post is done.

And now let's also cover put. All right. So HTB. Yep. It's also already suggesting that.

And I think Copilot is smart enough to give me something here. Let's say we have the update character. Uh in this case, yeah, we're actually returning a bool. But let's see how the result then is in the end. We're using the update character request.

This is true. See now I'm actually just reviewing the code that copilot has written for me. This is also something that I think a little bit this will be the future of us all developers but still you should know what is actually happening there. I cannot emphasize this enough. Now the updated character is await service update character async.

This is true. If we have an updated character it returns no content. This is correct and not found if something went wrong. Right? Right. So character with the given ID was not found.

Okay. Let's do it that way. And then we also have delete as well. We have to add the ID here. And here now it is doing the following.

It's pretty much the same, right? Yeah, I think this is correct. But now the interesting part will be the implementation here, right? So maybe even we also get suggestions from co-pilot. But we should really pay attention here. So now first well what we need to do now is we have our character request and now we have to map this to an actual character right. So let's say our new character now is character wait is a new character right using the object initializer here.

Nope not the character response it is a character a new character object that is not available here but now it is. And yes, we say the name is the character name. So again, manual mapping here. Maybe copilot can help me out. Then we got the role here as well.

And that's it already. And now we can access the context characters. Add new character. And then we also have this is important. We have to save this, right? Because with this method here, add nothing is stored yet in the database, right? It just adds the uh it's tracking the new given entity.

All right. Then save changes async. We have to make this method async here. So the error is gone. And then we want to return this, right? So we return the character response.

So again we map this. And the big difference here of course now is that we send the name, the game, and the role without an ID. And with safe changes async then we will get an id and then we see that in the response. So now it does make sense even for this example now to see the ID in the response. And since this is crucial I suggest we we test that real quick.

So back to scala reload. We see a bunch of new methods. Right. So again real quick is it running? Yes. we get the uh the game characters now with that ID and now let's say we call our post method and here again let's try it with Zelda from the Legend of Zelda and she now is a princess we had sent and we get this back 2011 created this is the object and this is again by the way this is now the the body, right, that we want to send in JSON form.

So, let's close this and then check this out here. Test the request. We hit send and there's our beautiful princess. And now we can also uh get the single entity with ID4. We hit send and there she is.

All right, this is great. So now we only have delete and update left. So let's continue with updating first. This method shall be async as well. And it is suggesting something here now.

So existing character. Yeah, why not? This works. If it is null, it returns false. And also it will Yeah, actually I just have to think a little. Yeah, this for me this works.

Now the thing is as always you have a bunch of options here. It is trying to get the character with the find async method. We have the ID here, right? This one is given and this one is given here as well. Now in the update character request object, we also could do uh the following since or with that update request we have the ID here. So we could double check is everything correct here.

Right? So when any kind of front end says I I put the ID here and also in the character request object then the server should make sure that the ID is the same. Okay, let's let's say for double safety. Okay, but in this case, this is also sufficient. I think you know it is grabbing this ID. It tries to find this thing.

If it doesn't find it, then it returns false. And otherwise then, and this is the crucial part, it will override the properties here, the name, the game, and the role. And then again save it. And when this worked, it returns true. Of course, you could also surround this by a try catch block and return false if something happens or well just throw an exception, right? Lots and lots of stuff you can do here.

But in essence, this works. So, let's save it and test it real quick. All right, so let's say we again uh have a look at Zelda. Yeah, I need an ID. Okay, Zelda it is.

So, let's copy that. And now put test the request. And here now we say um we got Zelda the legend of Zelda and she's now not the princess she's also a hero and we have to put the ID here. Now this ID is not really that interesting right so indeed we could also use the create character DTO this would totally work. You're not doing anything with that value here.

So let's just say we sent this and we get a no content back. Now this means everything should be fine right? Also one thing one little side note I know that you know there are these rules in the world of web development where you might hear that you shouldn't return something here so no content but sometimes you know to save a little bit of time maybe or requests database what you could definitely do is just return the final object because you want to see the result anyways right so again something to think about but Now when I try to get Zelda here again with a D4, there it is. She is now a hero. Nice. So this works as well.

And now the last thing would be deleting a character. So there we are. Now this will actually start pretty similar to updating because we have to check for the character with the given ID, right? Is it actually there? And since copilot is not suggesting anything here, let me just copy this thing and put it here. And again we check for an existing character. All right.

Then well maybe we re rename this in that case. So here now we can just say this is our uh character or character to delete. You could also say down there character to update stuff like that. We don't set anything here. So we try to find this thing and then if it's not found we return false and then here before saving anything we say context characters remove character to delete.

This is exactly what I want to do. So the remove method then begins tracking again just begins tracking that this thing gets this deleted state and with save changes then it runs everything that was tracked right. So entity framework is doing its magic. And that's it. So let's just test that as well.

And by the way, while it is restarting, we could of course uh double check here. Right? So here Zelda is there as well. And now let's go back to our application. Reload. And to double check again, we see here with value four, we got Zelda now persistently stored, right? It's not a static list.

that gets deleted or any entry gets deleted when we save something there and then restart the application. And now we want to delete Zelda. No content comes back. And let's try let's try to get Zelda with ID4. And the character was not found.

We can test here as well. Only three characters. And same thing here. Zelda is gone. All right.

And for me now the next part actually would be to know how would this work with copilot. So we have this copilot chat window here right and how can we use copilot to build such a web API with entity framework for us or how can we do it together with copilot and if you're also interested in exactly that and you want to see how this is done by me then check out this video here on the screen. Go ahead I can wait. Got some coffee left.