Minimal API in .NET 6 Using Dapper and SQL - Minimal API Project Part 2

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
minimal apis are a new feature in net six and we're in the process of exploring them in this two-part series we're building a complete application that consists of a sql database a data access layer using dapper and a minimal api in the front end this is part two where we wire up our minimal api for full crud access if you missed part one go back and check it out now this is the first video you've watched of mine my name is tim corey and it's my goal to make learning c-sharp easier i provide videos at least twice a week here on youtube to help you grow as a developer i also have a full set of training courses on iamtimcory.com i encourage you to check out all the resources that i have to offer now in this video as with most of my videos i'm going to create some source code if you'd like a copy of the source code use the link in the description okay let's go over to our code and get started now just a quick recap where we're at again if you haven't watched part one please do because otherwise you'll get a little bit lost as to what we have in place but let's go over real quick we have our sql database which we use a sql database project to build that way it's in visual studio it's in source control if we put this under source control i don't have source control applied to it but you can and we have our one table we have our five store procedures for the full crud access again if you don't know crud stands for create read update and delete it's the major actions you perform against a database whether it's getting data out or putting data in now we have a deployment set up in case we want to publish this repeatedly we've already published it once and that's in our sql server object explorer right here minimal api user database and we have some standard sample data in there right now that just has a few records in it so if you go to tables user and say view data you'll see we have four records here tim sue john and mary and that's just we have something to work with when we first launch our api now we also have a editor config here and this the primary reason for this existing is so we can use the file scoped namespaces which is a new format as opposed to the um the block scoped namespaces which would be the traditional way of of using namespaces so you can add more of your own styling here if you'd like and that will apply just to this solution we also have a class library called data access where we have our sql data access this is what this is where dapper talks to our sql database and it really is fairly simple in the fact that there is our really one line maybe two lines to consider or count connecting to the sql database there are two lines of code necessary to talk to the database and get back data in a set of models and here is our two lines of code to store data in sql and that includes using parameters i had a question earlier about that yes that includes sending parameters to our sql so that we can insert things like first and last name or update a record based upon id and so on so that's our save and load data method we use this in our user data class where we say hey get users get a single user insert one user update a user and also delete a user this class is what we'll be calling inside of our api actually using the the interface for this class so we'll have these five methods available to us in our api which should make things rather simple when it comes to making the calls okay so that's where we're at we do have we can collapse down all of this and now we're down just to our main project which is the one set is startup project if yours says startup just right click on it and say set as startup project but this is our api let's close all tabs here that way it doesn't keep open backup this is our api and our api has very little in it to begin with because it's a minimal api in fact we have primarily two things app settings.json and program.cs that's it for api we're going to add a little bit more to it and make it actually functional but even in a demo state it will work right out of the gate but first let's do this let's go over to our sql server object explorer select our database and then go over to properties and in properties we expand out a little bit we'll see that the connection string right here if we double click and copy this that's the connection string to this specific database now i'll leave this in my code but for you it may be a different connection string so don't just use my connection string do the same thing i just did select the database and go to properties and copy that connection string that's your connection string then uh on your computer for your database so put a comma after allowed hosts in my appsettings.json file and quote say connection strings and in here i'm going to say default remember that's the the default value we're going to use and that's a paste in my connection string so when we ask for the default connection string it's going to give us back this string which is a lot of stuff in here really you could have a a simpler connection string if you didn't want to specify subnet or multi-subnet failover an application intent and so on but by copy and pasting it's really easy and it gives us all we need and more so whenever we refer to the default connection string now we'll get this back which by the way if we go back over here to sql data access and look the connection string id the default value is default so when we're asking for a a connection string right here we pass in the connection id which is this parameter but if you don't pass anything in for it which we're not then it defaults to default which will get this connection string because that's where that name is if we call this um i don't know sqldb then we have to either pass that in to our calls to load and save data or change the default here to sqldb so just let me clear on how that all works so we have our connection string now now we can talk to our database let's close both of these out we can minimize this again and look at our program.cs now this comes with some standard boilerplate template goodness just to show off what you can do with your api so if you look down here first of all this is collapsed this is um a new feature of net six which is has collapsed the startup.cs and the program.cs into one file it's also using that top level file where we don't see a a static void main we don't see the namespace wrapping we don't see using statements it's this is all essentially this file program.cs is the startup file and everything in here is in a hidden static void main in fact it's a static async task main so you can do asynchronous tasks in here but it's all hidden it's just um it's assumed because of the fact that our starting point for every application therefore we want to specify that if we don't want to so with us all being in that one method this is going to configure our web application we're going to add dependency injection we're going to build out our app to start so that we can access our uh configuration information then we're gonna check to see if we're in development mode and if so are i use swagger inspire ui and that's that open api that's the um the idea that when we launch this application and let's just do it right now because why not so we'll say launch minimal api which is going to launch kestrel as our our web server and then it's going to launch the browser with our our api once it does and it seems to have popped up underneath here but there we go this is our um our swagger so by default we go to swagger page which notice the url if we can't see that let's zoom in here uh localhost note that now kestrel and.net 6 or actually it's in visual studio 2022 i believe um it changes the um the port number for kestrel to be a randomized port inside of a range in the 7000 range so that's instead of being 5000 and 5001 which used to be 4.net five and below so i think it's both a net six and a visual studio change i'm not positive but anyways it has changed how about that and then we do swagger and slash index.html this is a default starting point for our apis so that we can visually see the structure of our api and even test what's going on so you can say click on get weather forecast and say try it out and just execute since there's no parameters and notice that down here it has returned a whole bunch of data to us in the response body with a code of 200 meaning success so that's the api actually running now that's running with test stuff we're going to get rid of that now that's swagger i'll show you that we have https redirection which means that we're going to not allow the user to say http for our site if they do it's going to redirect them to the https version of a site we always want that on now here's where our test data starts we have some test data here in an array and then we have app.map git and what this is is our our api endpoint so instead of having a controller that has then our information in it we have this idea of an end point the difference between controller endpoint a controller has the full information for a set of end points essentially or a set of uh places you can call whereas this is saying hey map get which means this is gonna be a get call and i want you to map out this specific path and so if you type in your localhost colon whatever the port number was slash weather forecast you will call this endpoint and it will return forecast which is a i knew or enumerable of five elements and it's going to create just randomized uh weather so we're gonna get rid of that that is sample code as is this summary section here so we'll get rid of that and we also don't need now this internal record the weather forecast get rid of that so now we've gotten rid of all of our sample code but we're not gonna have anything then to run with our api that's where we're going to start adding things back in the first thing we'll add in is a dependency so right click on dependencies and say add project reference we're going to select the data access library and now we can talk to that data access library to do that we're going to say builder dot services not add the nbc we're going to say dot services dot add singleton and we'll say i sql data access control dot add a using and then sql data access like so and then we'll say builder dot services dot add singleton for i user data and user data control dot to add that using statement and then like so so it's gonna add two things to our dependency injection system first of all our i sql data access and then second of all our iuser data we're gonna use user data to talk to our our data but we need to have this in our dependency injection system our isql data access because it needs to be injected with our eye configuration and the user data needs to know about it because it uses i sql data access so those two entries need to be in our data access system now right now we have not used any global usings and this might be a place to start using them because the fact that we may we'll have to use the data access.data pretty much everywhere because it's something that's going to be we're going to have access to eye user data i don't think we'll need i sql data access anywhere else so we'll leave that one alone but data access data we will and data access dot models since we getting back that user model so we could put the global using here we could just say um global using like that and leave it here but i'm not a huge fan of putting in program.cs because the fact that we're now adding one more thing to program.cs and it's getting pretty packed i i really kind of like program.cs to be a little less packed in fact i kind of liked the startup.cs idea better but no one asked me so what i'm going to do is i'm going to create a new file in my project so add new class and the convention is still for me on this i kind of prefer usings.cs some people prefer globalusings.cs i'm going to do globalusings.cs because i've seen that preference a couple of times now but i kind of prefer usings.cs so again if anyone's asking for my vote i vote usings.cs it's a little simpler but global usings dot cs and we're going to take away the the namespace and the class take away everything and then we're gonna grab this global using we'll cut it out here and we'll put it over here now what does this do for us well now we have access to eye user data without having to add a using at the top of the file so if we didn't have this let's comment it out real quick then this right here would throw an error see it's saying hey i can't find that but now we can have it accessible for every place that we need it in our application not just this file since we're going to use it all over our application that makes sense don't abuse the global usings but it is something you can take advantage of when necessary so i'm going to take another one global using data access data not sql client uh dot oops i'm sorry data access dot models there we go now right now it's not being used and it's intelligent enough to know that but we will need that shortly so i'm going to add that now so we're ready to go and with that we are almost done the only thing we have left to do is our actual api endpoints now i could put them right here on line 23 and you'll see a lot of demos do that i'm not a huge fan of that but again because we're getting program.cs to do pretty much everything remember that this is a a method it's one method and its job is now multi-part its job is to launch the builder its job is to register services its job is to build the application its job is to add swagger if it's in development mode its job is to handle https redirection its job is to run the application and if you use the defaults its job is also to configure all the endpoints with all of their methods i think that's too much so i am going to separate this out into a separate method i'm going to move this into let's create a file called apis all right so apis where's api how about that now if you're going to have multiple of these then you might want to consider doing something simpler like having one per grouping of end points but again if you get too far down this rabbit hole then maybe you got a more complex api which would require controllers as opposed to just end points but we're trying to keep a minimal api so we have just one class called public class api i'm actually going to make it a public static class and that way we can reference it in our program.cs and i'll show you how to do that in a minute but with this i am going to create a public static void configure api and we'll pass in this web application app now why am i making this method and what's it going to do well this is where i'm going to do all of my mapping okay is in this section which then allows me to come back to my program.cs i'm going to say app dot and then the um the name was oops configure api so i can come back over here and say app.configure api like so and we have to add a using statement using minimal api demo so by registering this and then now we say configure api so we have use https redirection configure api and run this is more this down here is more the pattern i like to see in my program.cs files which is that's essentially a quarterback method if american football then the quarterback is the person that that calls the plays executes the plays and uh tells things where to go and and so on so with this it's saying do this then do this then do this it's not actually doing the work it's just telling somebody else to do the work it's a manager and it is managing every step and it's very clear what each step is when you get into stuff like this i'm not a fan because it's doing the work and as a manager you want to be managing the process not also being a hands-on manager so not a huge fan i'd i'll probably end up moving these out into their own service file but for now i'll leave that one alone we'll just concentrate on the end points themselves which are all going to be in here and make things a little bit easier okay so now we need to start creating our endpoints this is where it gets fun we could do it in line but i'm not going to do it in line i'm going to create a separate method for each one of them that way again it separates out our our logic from the call or the configuration the wiring up of our endpoints so i'll create one you'll see how it's going to work so private static async because it's an asynchronous method and we have to add a um not sure what you want me yet we'll wait for that async task of i result and get users i user data data so this method right here is actually going to ask the dependency injection system for eye user data remember that i use your data is this right here which gives us our five methods so it's going to ask for that and this method is going to called get users which gets all the users let's wrap this in a try catch now we're not going to do much with the exceptions here um except we're going to say return results dot problem ex dot message so we're going to say hey it didn't work here's the reason why and throw that message back to them so you'll get an error message properly formatted in the right in the right error code and so on let's try catch we're going to say return results dot okay await data.getusers that is our entire endpoint for getting all the users in the database it essentially comes down to one line this right here return results.okay what this is is wrapping the results in a a http message of 200 saying success you don't have to do this you could return just the actual results in which case changed your return type but by saying i result we're able to wrap all of our things with the proper http codes that way we can be more specific as to why things don't work or why they don't have access to them and so on so the ok result says success now i'm returning that right away but if something were to happen in here where it crashes we follow the exception and return a problem that that gives us our our message as well so that's how we're going to handle the error codes to properly give back a return if you want to really cut this down you could just say await data.getusers and just have that as your endpoint but again you're missing some of the nuances of properly returning codes and also you can do logging in this catch and so on so this sets us up for success in the the short term and also the long term it's it's the way to start small and yet have it be expandable for what you need in the future so i recommend this pattern over just a one liner like returning that so with that up here we can say app dot map get and we'll say slash users notice the plural there and get users so that's now our endpoint mapping we're going to say hey i want you to say slash users when you do we're going to call the get users method which does this call right here it talks to our database that that's the entire talk to our database it's just hey go ahead and do it that's it so again no sql knowledge here it does not know where talking to sql is not nowhere talking to anything it just knows i need users i'm going to await the result of those users and if we have success we're going to return an okay message with those users attached and if not we'll throw a prob or we'll return a problem with that error message so that's our first end point ready for the second one second one actually has some parameters to it private static async task of i result get user int id and i user data data now in this case we're asking for two different pieces of information and i love the simplicity here because this i user data comes from dependency injection whereas this int id comes from the user comes from the call to the api so it's mixing where it's getting the information from flawlessly so we have asked the user for the id we're getting this independency injection and now we can essentially do we just copy this and paste it down here and we can uh modify this so that we actually have our proper call so we got the return result.problem stays the same but here we can say var results equals await data dot get user passing in the id and then if results equals null i'm going to do this in one line just to kind of stay in character with the really thin thin wrapper return results dot not found again returning a um an error message that is really simple okay so that that error message is really simple just not found but it's going to return the correct http response code for not found and then return results.ok results three lines that will first of all get the results from the user make sure that they're not null and return not null if not found and then return okay the results if they are found yes we collapse all this down into one line of c sharp code i think that's a little too much collapsing for us but i think this right here gives us the right amount of of simplicity while not being so simple it's actually confusing or so simple it's got too many lines of code that are unnecessary so that's now our get user which means we can come back up to the top and say app.map get slash users slash curly braces id and that will get the id right from the url and get user and now we've mapped our second endpoint this one asking for information from the user and based upon that we'll return back one record based upon their id or no records if nothing was found so that's now our second endpoint we'll just keep going so and notice by the way these are private which means the only thing being exposed from this api static class is configure api that's it even though we're using these private methods and mapping them onto our endpoints we're only ever exposing configure api that's it to our callers so over here we say configure api that's the only thing we have here in our configure ap on our app so and yes we are using this as an extension method uh that's why this is in front of it we're adding that onto the web application type that way we can extend that and add it on to our options for app so with that let's come back down here for our insert private static async task of i result insert user one word and user model user notice that's coming from the global using so it knows where that is and then i use our data data inside of insert user we will let's do our try catch again here it's the same try catch except for the what's in the try itself so await data.insert user return results dot okay that's it okay we have essentially done in one line which is just insert the user and then return okay and if anything were to happen we drop down to our exception now let's keep going we'll keep working on our um our methods and we'll go back up and map all of these so let's stick with the the pattern here and private static async task of i result and we're gonna say update user user model user and i user data and we'll paste in our try catch we're going to say await data dot update user return results dot okay so again always hit is update user it's one line and then we say okay if that succeeds and if not we return our exception so last one private static async task of i result delete user int id and we're also going to have a i user data data so pass in the id and we're again paste in our try catch we'll redo this to say await data.delete user passing in the id and then we'll say return results.okay notice it keeps learning what i'm doing and get a little better each time at giving me the full line completions so really cool stuff in intellicode there that's our delete user and so that's all of our methods are done now and we're passing in the full user model we get from the user so this user model comes from the user in our body whereas up here let's see in our get user we have it coming from the um oops right here we're passing it in through the command line or the command line url we're passing in the id and that'll work for get but we don't want to do that for other things like update or insert update or delete so we'll pass it in through the body and yet it's still in that same parameter list it still figures that out understands it and properly processes that information so really cool stuff there that is really really intelligent there's a lot of intelligence behind this that makes it look so simple so we now have all of our calls we just need to map them so let's start doing that app.map post that would be for our insert so slash users that's it and then insert user so again the different verbs for http we have our get which is for reading data our post which is for inserting data then we'll have app.map put users and then oops update users update user and then app.map delete and again users delete user so that's our entire set of mappings for our endpoints we have five we have two read actions a read all which is the the first one get users then we have a read one which we pass in the id on the url for that and then we have these three which are post put and delete and these are our insert actions these are actions where we're saying did to sql as opposed to or to the api as opposed to getting it back out now you may notice that the path for all of these is slash users and the only one that's different is this one where it asks for the specific id the reason why is because we're using different verbs so get versus post versus put versus delete this is the way i do an arrest api in a way that is uh prop calling the proper noun or proper actions for an api so when you delete a record you should be calling the delete type not just a a post now if you get lazy you could call post but the nice thing is by calling different verbs that you can use the same path slash users and just use the different verbs to indicate what you want done now again we're not telling these three hey you need to have that model inside of your inside your body but yet down here like an insert user we're getting that model and update user we're getting that model and delete user we're getting that id which is in the body so it handles that mapping for us without us having to explicitly say where things are at and guess what we're done so if we run this we should see our application up and running hopefully it's going to pop up on the screen we'll see hey there we go and now look at our minimal api demo it actually has five different actions on the screen for us we have our get post put delete and other git let's start with our get here we just hit try out and hit execute and if it works which it did that's awesome first time working we get 200 response back saying yes success and then we see we get four individual objects back we've got tim corey the idea of one then sue storm id of two john smith was three and mary jones with four so our get all works now if you come down to our other get when we say try it out we have to fill in the id now remember tim is one sue is two i forget three and four let's find what door three is so we put number three in the id field and hit execute and we also have a 200 down here so we are successful and then we can zoom in here and see the id of three is john smith okay let's let's find what 4 is we come up here and change that to 4 execute again and then come down here we see that 4 is mary jones so this allows us to try out our api and allows us to see what the structure is for what is required so this game really helps swiger can be really helpful for just visually looking our api but it also allows us to build out actual c-sharp endpoints to talk to this api using the swagger information so really powerful stuff here but then let's try the other ones make sure they work so post let's try it out and it says this is the intelligence here again it says hey you need to send back this information id first and last name now id is zero we'll leave that alone but let's go with a first name of [Music] karen and last name of dior i don't know there we go um so we now have a new record we want to insert we're gonna hit execute we'll come down here we see that we have a 200 response which means success but nothing else just success so how do you know if it worked besides that message we come back up to get all users we say execute and we come down here and see that karen is now number five so we have a new user number five now we can do a a put so we can try it out and the put is for our updating of the record so let's zoom in here we have to change this id to whatever id we're modifying let's change five we'll keep karen as the first name and the last name is well it's actually smith okay so we got the last name wrong we change that we hit execute we come down here and we see again success how he knows successful come back to our get all execute again scroll down we can now see that karen's last name is smith so we've now done update and let's collapse that down we'll do a delete and we'll get rid of poor karen so put 5 in there and hit execute and we have a 200 success on that again let's prove that by coming back up to our get all hit execute again and noting we now have one through four and number five is missing so our api is fully working in our setup so we didn't have to do a ton of coding today even though yes there are some um some complexities in knowing how to put things in different spots but the actual work was all done in the previous lesson when we set up our data access which by the way remember that data access will work with any user interface except for webassembly but um we can hook that up to any ui project so wpf for win forms or razer pages mvc uh console application a worker service all that good stuff they can talk to any of them but in our case we hooked up a minimal api and then this minimal api really is minimal so we have our program.cs which we have two services we've registered we have one line here that says configure api we have modifier app settings to add that one connection string and then in here we have our global usings just to make things easier we have our api.cs and this api cs has one method that's public and that is maps our five endpoints our actual endpoints are super simple they essentially have one to two lines of one of three lines per uh entry but let me wrap that and try catch to be good citizens and return the right error codes if necessary return the okay properly if we get the right values back and so on so we've done we've created a full api that talks to an actual database that gets actual information in and out and yet it's a very very minimal setup so this is what a minimal api would look like now you may have a little bit more code here where you might wrap or add logging you might add a couple other things but if you're doing any kind of real coding where there is more work in in this try section than maybe two lines of code or three lines of code then i would highly recommend you put that in your business logic section not in your api and then just call that one method move as much as possible into your class library so that other projects can take advantage of it and to keep your user interface as slim as possible so that's it that's a minimal api that's what i recommend now a minimal api when would you use this so we talked about before but i want to kind of cover this that minimal apis are really helpful for things like microservices where you need to do a little bit work and it's a little bit beyond what an azure function can do where you have to have more than one endpoint well in that case you can create a minimal api and in just a few lines of code i mean this is the biggest section right here most of us boilerplate but we have 79 lines of code and that's the biggest section of our api endpoint and we have full crud access against the database so yes one table so you'd have a lot more if you have multiple tables but at that point you're getting beyond what a micro service is doing so for microservices this is really helpful because you don't have to have a lot of setup stuff you can have you can really template this and not even change program.cs just modify the uh this section right here and the methods that it calls and that'd be it and you could have multiple apis you can support really really quickly and yet they focused in on one microservice and servicing that one microservice properly so that's a great place to use it but even just having a small api this is the way to start i think i would start with with the end points and figure out if you need to expand the controllers i'm thinking for a lot of cases you probably won't need expanded controllers if you need to not a problem you can definitely do that right in your api right in this api you don't have to do a new project you can expand to controllers not just endpoints but if you start small like this and work very hard to keep things lean i think you'll find that your user interface portion the api should will stay pretty lean and pretty small and that's a good thing you don't want your api massive you want it to be lean you want to push everything down to your class library and let the class library handle all the heavy lifting that way you can easily swap it out later you can put other things against that class library not just your api and so on so i think this is a great addition as an option and it makes things a little bit cleaner a lot cleaner and a lot simpler and removes a lot of the boilerplate stuff we just don't need in most circumstances so that is part two of wiring up the minimal api it's this project is a full project it talks from from database all the way through the api and back but at the same time there's not a ton here because we do want to keep it as lean as possible thanks for watching if you have any questions or comments or thoughts post them down below in the comments i'd love to hear it as always i am tim cory [Music] [Applause] you
Info
Channel: IAmTimCorey
Views: 19,812
Rating: undefined out of 5
Keywords: .net, C#, Visual Studio, code, programming, tutorial, course, training, how to, tim corey, C# course, C# training, C# tutorial, C# app start to finish, asp.net, .net core, dependency injection, minimal api, c# minimal api, mapget, mapset, mapput, mapdelete, map get, map set, map put, map delete, .net 6, minimal apis .net 6, asp.net core 6, visual studio 2022
Id: 5tYSO5mAjXs
Channel Id: undefined
Length: 48min 25sec (2905 seconds)
Published: Mon Nov 29 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.