Minimal API +SPA, a perfect match | .NET Conf 2023 Student Zone

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hello everyone and welcome to today's NETCOM Student Zone session we're going to be talking about building with asp.net minimal API and single page applications or spars and why I think these two tools together are going to make for a perfect match for the kinds of application we can build my name is Aaron pal I'm a principal Cloud advocate here at Microsoft in the net on your team and I've been doing web development for many years now and I've had a lot of experience building single page applications in particular um because I spent a lot of time focusing on that kind of JavaScript side of it but I think that you know we we need to obviously make sure we're building back ends and I think that uh throughout this session today we're going to see how well asp.net minimal API will fit together but like I said I'm I'm a bit of a front end guy so I want to start with that and that's kind of where I want to contextualize the problem space like you're building a front and web application using kind of the modern JavaScript libraries to build that so we're going to be building an application with vit vit is a tool for um kind of scaffolding and then building a an application using what kind of whatever JavaScript library you want to use for building uis we could be building this with react or spelt view or a myad of other ones that are supported with v um today we're actually going to be using react just because that's the library that I'm more familiar with and and I prefer to build with when I'm building uis um but you could easily take the patterns and the the design that we're covering off in today's session and apply that with a viewer application or anything else because we're focusing kind of on that single pager application and the apis that are going to support that speaking of apis first to be building a application if we're building a single page application we're probably going to need to get data from somewhere otherwise we're building just a a fully statically rendered web application and that's sort of outside of what we're covering off today so we've got V that's going to be building out our um HTML CSS and JavaScript and kind of generating those files for us but then we want that backend service and this is going to be a net application and I said we're going to be using the aspnet minimal API we'll see how we can build a couple of apis and then make those available to our client application and we're going to be doing that over just HTTP um I'm going to just use the fetch API that's built into browsers but you could be wrapping this with a library to improve the way that you do um HTTP requests and responses such as like axios or things like that um but I want to keep this kind of as agnostic of the Frameworks that we're using so that you can you know pick and choose the the right tools that are going to be needed for the application that you're building speaking of how we're building this application we're going to be using vs code um mostly because I again I'm I I do a bit of front end development here and there and and I find vs code is just it's the best tooling that I've used for doing frontend web development for many many years and I think that if you're coming at this problem space from that kind of web development perspective you're more likely using vs code than anything else and with vs code we combine that with the extens extensibility model that it's got and bring in kind of those extensions that we want when it uh when we building out our application we could bring in things like preter or an eslint so that we have our style guide and we're applying the coding um design that we want we're making sure that we're not introducing things that are going to break the kind of coding standards that we have with inside of our application but I'm then going to combine this with the new C extension that we've recently released for vs code you could also add the V the C dev kit to vs code and I'm going to be using that with inside of my demos just because I like some of the additional features that that brings in um but you don't need to use all those if you don't want to you can just use the new new free open source C extension devit just adds a few more things over the top of it that if you're coming from like a visual studio experience you might be looking for I think though that's really enough slides for today because I want this to be a very Hands-On um activity so that you can build an application and that's what we're going to tackle into next if you want to follow along um live or live as the recording could be you can jump onto the GitHub repo at AKA Ms NETCOM 23 student repo and then inside of that you'll find the 2023 folder and then um the the folder to this particular um application that we're building you'll find there both the starter version and a finished version so if you just want to jump to the end and see the completed application you can do that but obviously I'm going to start with the starter kit and we're going to be building from there I said that's enough slides let's jump over to vs code so here I am here I am in the uh starter project that I've set up and uh I've gone ahead and scaffolded out a few things that we're going to be needing here mostly so that we don't have to watch like an mpm install mpm create and netu and a few things like that I have a front end folder and this is our V application that's been scaffolded up for us uh this is building with react as I said before and I'm also going to be using react with typescript so I've got like a TS config so it's going to be you know bring that type safety that I like a z. net developer to the frontend application that we're building uh but otherwise it is a standard v um scaffolded application with um with react and I've added two additional mpm packages fluent UI react components so fluent UI is a UI framework um for for building applications that we we use here at Microsoft and it's open source you can use it in your own projects mostly because I'm like I'm not a web designer I can build web uis but I can't make them look pretty so I wanted something that's going to give me a bit of a hand in that regards so I've brought in the the fluent UI for that one and I've also brought in DJs because we're going to do some date formatting in the application that we're building the other folder of major importance here is the minimal API folder and this is going to be our back end for our application um this is a aspet minimal API application that I've just scaffolded out with net new from the command line um the only additional thing that I've added here is this data folder and I've brought in adjacent file which is going to be the data set that we're building for our application so what I've got here is I've got the sessions export fromet com that's going to be happening in a couple of days time uh because we're going to be building a web experience of over theet com agenda allowing us to pick and choose which sessions that we want to kind of track and and and kind of add to a watch list so that maybe we're not going to be able to catch them live and we want to be able to find them later on and know which ones that we taged is the ones that we're most interested in and come back and watch those easily so that's what we're going to be building and uh to save having to set up a database or anything like that we've just got a Json file that we're going to be working with here we're going to be doing some write operations as well and we're going to write that to a Json file again just to save having to add a database but there's no additional dependencies that we're adding to this application so um like I said this is just a a c project that's been scaffolded up and we're not going to bring in any new new get packages or things like that now the other folders that I've got in here are just to make it a bit easier to work with with inside of vs code so I've got a vs code folder where I've defined our debug experience um so we can launch the front end and the backend application or we can launch the full stack um debugging experience which is going to start both front and backend servers at the same time um and we'll um connect those together and we can uh we can do a a single unified debug experience I've also included a Dev container definition so Dev containers are a way that we can define a development environment um that uses Docker or or a container orchestrator as the man for doing that this means that if you want to open this in a GitHub code space it's going to pre-install all the dependencies that you need such as net 8 which we're going to be using for our application here um I also am installing Net 7 just in case I have any um extensions in vs code that are going to still rely on that because at the time of recording net a is still in preview uh so some of the extensions such as the C extension and C C dev kit um not necessarily designed to work with net 8 they'll work together and that'll be resolved when net 8 is officially released I've also added to this that we're going to install node because I'm going to need node in here to run our front end application and then finally installing a couple of extensions into this I said you can open this in a GitHub code space and it's going to pre-install all of those or you can open this using the uh vs code remote extensions um and that will then preconfig your development environment with all these dependencies otherwise you just need to make sure you have those things installed and you'll be good to go with our application all right so let's just have a look what happens if we start our debuger so I'm just going to open the command pallet and say debug full stack we going to run like the whole application we're going to start everything up all right so here we go it's going to start up um the server so we're going to end up with two servers running and let's just pop this to the side we'll put vs code on here uh so we have um our backend server is running at HTTP Local Host 5181 and if we have a look in the program.cs file we'll see that we have one API at the SL API route or we have one route which is SL API let's just test that we'll see we got hello world let's Zoom that in a little bit there we go so there is our back end like our back end's up and running but we also have our front end running here at Port 5173 we'll load that one up just zo that into and you'll see that this is just a I said scaffolded out V react application but we're not going to be using that we're going to kind of start everything from scratch or at least delete some of this boiler plate code and we're going to build up from there so let's just stop off our debugger experience because we're not going to need that just for the moment uh and let's start with the HTTP end point that's going to return the sessions to our browser so I'm going to create a string and we'll call this uh the session path that will be the path to uh data oops got my keyboard in it it is there there we go SL dat session eyes. Json all right so we're GNA that's the location where our files are on disk oh sorry that session data is on disk and then we're going to do a HTTP um map get oh sorry an app. mapg see I've got GitHub cop pilot running and you'll see that well AR that code pretty much looks like what we want if we see um let's just push this over a couple of lines so we're using uh system. text. Json if I add that using statement and get rid of our R red squiggly so we're going to be deserializing the uh sessions uh into into a type called session well actually don't have a type called session at the moment I haven't I haven't written that type yet um and if we go into the session eyes Jason let's just have a look at kind of what is the structure that we're going to need well clearly this is an array because what Don conf is over 3 days so we've got an array of days or um array of days where our session eyes data is within and inside of that we've got things like group ID and group name and then we've got the session uh oh sorry an array of sessions and sessions then has a whole bunch of properties and then one of those properties an array of speakers okay we've got a couple of different types that we're going to need to to have here I'm going to do a little trick here and make it very easy for me to scaffold out all of these types so let's just copy and paste that we only need one of the sessions here so I've just deleted the others for the moment going to come into GitHub co-pilot chat here clear off this and we're going to say generate some generate C sh types from the following Json I'm pop in that Json and let's see will it generate me some types okay here we go there we go it's going it that's you know that's pretty much the types that I'm going to be needing oops um it looks like it's it's triggered some kind of a filter response uh on that so I'm going to suggest that follow suggestion we're going to downvote that and instead let's ask it to generate with uh the properties as uh properties having the first character uppercase um I I noticed that if we if we have a look at these it's like ID with a lowercase i name with a lowercase n that's not kind of not really C coding um standards uh so I I need to reexecute this prompt um and uh to do that I'm just going to give it some more information try and fix that prompt fix the result that we're going to get out of there so let's kick that off again and see if it's going to generate me there well that's me some uh some better responses here we'll see that we get now capitalized values as expected and excellent we we didn't trigger off the um an error path or anything within GitHub co-pilot so fantastic let's create a new file inside of here and we'll add we go models do session session. C shop and come back to co-pilot here let's copy all of that in and we'll just close the sidebar down add a name space which will be minimal API models and then we'll paste all these in okay so I'm going to pull these out to separate files just because I don't like having one one file that contains everything let's just pull all these out whoops and we just use I'm doing control dot that's what's bringing up this little menu or you can click that light bulb um that's there move that to a new file just to illustrate so if I click that light bulb move to a new file and then last but not least we'll go session cross to a new file all right give it a moment there we go we've found that we have a list of sessions everything's all there excellent that's that's what we're hoping for now we'll come back to our program and we're not going to return a list of sessions we want well we want a collection of session eyes which is that kind of root type there so we'll just do session eyes and I'm just going to return that as an array and we'll see that it's Auto automatically brought in that using statement here all right so let's save that and let's just launch the debugger for the back end because we're not building our front end just yet but we'll start with our back end and see if that's that's working so that's all compiling down there our debugger is up and running and let's go to SL API sessions whoops uh looks like we've hit an error I have probably spelled path of that incorrectly uh this is you can tell that this is a live coding demo because I probably spelled something incorrectly uh session eyes session eyes Eddie no okay that was all correct by the looks of it um could not find path okay let me let me just make sure that I did spell that correctly oh and while we've got this file open let's just add all the sessions back in we'll undo that change that we had there and let's just paste that file name in okay ah whoops I don't need the I don't need the the forward slash on top top that that was then telling the file system to go to like the very root of our file system which is clearly not where that's going to be we'll debug the back end again and it's up and running reload Tada we've got well we're close we've got three groups there that is identified but well the group IDs are all zero we don't have group names we don't have any sessions so clearly we still still don't have something correct well what we're missing here is well that that kind of translation from Jason to C we'll see that group ID is starting with a capital G whereas if we have a look at back at our session eyes J file group ID is a lowercase G so we need to tell the the deserializer to handle that um properly so we'll set some Json serialization options we just call that serialization options and then um we will get it to well co-pilot can complete some of these for me um now we'll see that it's add some stuff that I don't need such as write indented because we're not doing wres I'm just doing um reads at this point so I'm going to get rid of right indented and we're going to say um case we'll add the property name case insensitive thing and it's kind of mutually exclusive I guess saying camel case and um case insensitive but I'll just put them both in there debug uh the back end again oops just realized one other thing I might have created serialization options but I didn't actually tell the serializer to use them let's add that in and we'll add in the serialization options all right now we can start our backend again see how many tabs I can end up open uh as it launches each time there we go Tada we've got our backend running and it is returning us all of our data excellent now we can go ahead and build our UI well actually before we do that I just want to talk about the fact that we're reading a file from disk so this is going to be a pretty quick operation but I I could be reading this out of a database and in that case maybe we want to do this as an asynchronous operation rather than a synchronous operation we don't want to block any other potential incoming requests obviously for for a demo application like this we're not going to have a whole bunch of traffic load but we can change this instead to make it async function async and then from this instead of doing read all text I'm going to extract that out and use a file stream and we'll call that file stream equals file stream open the session path and then we are going to pass in the file stream to here but instead of deserializing synchronously we're going to Der serialize asynchronously and then we'll say a wait on this so now we've made this a asynchronous operation just to demo we debug the back end um so it becomes a non-blocking thing so if we I said if we were talking to a database maybe you want to be pulling it that way um and we'll say that everything is still working exactly as we were expecting but it just means that you know we can handle more traffic for our little demo application here all right so we built our back end our back end's able to serice sessions let's go ahead and build the UI so I'm going to come into the app. TSX and inside of this is well the scaffolded out V code that we had before let's delete this all back because we're not going to need any of that and we'll delete off the set State uh that we had there but I will use I'll be using state so I'm going to going to leave that inside of here now let's think about what we've got to do from the UI the first thing we need to do is we need to go and pull the data back right um but we're going to need to kind of indicate to the user that we're doing an operation we're going to be fetching out some data so for this I want to kind of track a couple of different um State transitions that um our data fetching could go through uh so for that I'm going to use a typescript enum so I'm going to create an enum called load State and inside of this I want to have well um I don't like them being uppercase so I'm going to say not loaded so initial page state is that we haven't attempted loaded data and then we're going to have loading we're fetching our data loaded and then lastly we're going to have an we'll put in error St but we probably won't Implement errors that could be an exercise uh for you as the viewer so we're going to go ahead and create our data load State and look at that co-pilot has uh has added that in for me and it's set the initial State as not loaded and then we're going to create some data and set set data and we'll say use State um and that can be an array but again like we don't have any any types here because well we generated some C types but what about generating some typescript types well again let's come back to copal and say generate typescript types from the C types types all right let's get it to let's see how is it going to generate oh look at that we are getting a whole bunch of types there let's copy this we'll come into our application and we'll add a new file go models do SL session eyes TS and again I'm just going to pull these out into separate files just because I like them being in separate files move that to there move that one to a new file and last but not least category item now mly we're not actually going to use a whole bunch of these types so I could have you know kind of written that out myself but I liked uh I like having all of it in there because you know we could expand the application in the future now something I did notice on the speaker sorry on the session item here is that we have an any because we actually don't know what question answer could be I'm going to delete that because we're not going to use question answer at all so I'm not going to try and generate a type for it so we're just going to kind of have that one ignored close off my app. ts um just while I was trying to close everything there but that's not correct I want sessione array so that is going to be the type of our data right we're getting we're getting underway um but let's just go and start building out the UI net comp session selector Port that uh and now because we have that data load State we're going to say go if the data load state is not loaded let's add a spinner bring that spinner in from fluent UI because well and I'm not not a UI designer but I can pull in that from a library and we'll start up our back we'll start up our whole application let's get ready let's get ready to start actually seeing these changes happen in the UI I do have it running here so let's just reload this one see what our UI now looks like in a moment or that tab might have actually timed out because um it had been off been close s excellent we go we have a spinner and let's open up the dev tools here at the bottom see just how cramp we can make the screen on the recording um but there we go okay so the spinner is there um so if it is not loaded uh actually if it's not loaded or we're loading we're going to want to show that spinner or the data load data load State equals to data load state of loading there we go okay so if we're loading or we're not loading then we're expecting a spin to be there now it's time to get some data and for this I'm going to use an effect hook in uh react oops H there we go and we will put our squiggles in and I only want this to run on the initial component mounting so I'm just going to pass in an empty array of dependencies okay so we're going to need to go out to the API and kind of do what get up co-pilot has just suggested except um it was it was suggesting for me to do something just with kind of this the the inline like then then then um approach to working with promises but I'd prefer it to be an asynchronous function so because the an effect has to be synchronous we'll create a inner function for that called Fetch data and let's see oh look at that Copa again we'll just write it all for me kind of feels like cheating although that's not what we want to hit just some random sessionization uh so we are going to pull that all in yep that looks all correct fetch data let's load that up okay cool we've we've attempted to get some sessions um if we have a look at the response just like we can see that that's come in there we'll come to the response and we'll see that we that doesn't look like Jason which is what we expected and we're also getting two of those let's one problem at a time one problem at a time we've we've got uh we've got Jason we're expecting Jason but we got some HTML well why did that happen um and I suppose this is actually where if I had been implementing an error State we'd probably see that um why why does that happen well we're hitting this end point of API sessions but the that thinks is part of our react application here when realistically it's part of our API application uh and that's running on a different HD so what we need to do is we need to tell um our VA application the where to find that um now we could obviously pass this set this as like HTTP call like the path of the port we could maybe inject that as an environment variable but then we have two independent Deployable units in the future if we deploy this maybe to my a static web apps we want to treat that as a single deployed unit and I want to be able to go SL API slash to get to my API I don't want to have to deal with like um CS or anything like that so thankfully I can just come into uh my V config and I'm just going to copy a v config that I have pre-prepared and then talk about what I've done um what we're doing is we are going to be Lo using um an environment variable so we're going to be loading this environment variable here and then uh we're going to look for environment. API URL otherwise we're going to fall back to that now I have actually set that um environment variable with inside of the launch config so when I when I'm Lear loading up the front end application it's injecting this environment variable of apiurl which is the end point of our HTTP back end so now we can just pull that in we can treat this as a single uh application and let's see that looks like we have got some Json back one one step closer the only thing we're missing is the fact that it's well it's it's calling this end point twice now the reason that it's doing that is because I'm running react in strict mode and strict mode will Mount the component and then unmount it then mount it again just to simulate the possibility of um of State transitions really quickly and allow you to catch potential problems such as this so what we want to do is when this component is unmounted like if it was to to drop off screen we want to then get rid of that previous fetch request we don't need to to wait for the response because we're not going to do anything with the data so what we want to do is we want to abort this fetch request and we can do that with an abort controll so let's create an abort controller and that will be a new abort controller we will pass the abort controller signal as the signal to our fetch request and then finally I'm going to return from this um effect a cleanup function so if this um component is unmounted this return value will be executed of this um effect and it will abort our um it will abort our fetch request so let's load that up now and we'll see that the first one now has a red X against it because it was aborted and we'll see that we didn't actually get any response because we we canel said request so just a good little tip that if you are running um if you are doing kind of data loads like this you probably want to make sure that you're not accidentally executing more requests than you need and um and using some like an abort controller so that you can cancel requests is a really good idea all right so we've got our session data there it's time to start displaying sessions so let's go if the data load uh not if it's Error we're not going to worry about error States if it is loaded we are then going to return a new component here and I'm going to create a new component we'll call it session eyes list and that is going to take the uh data which and we'll pass that data in there so let's come into our uh tree here and we're going to create a component SL session eyes list. TSX and let's create that component export const session eyes list and then we'll return a component now I can create a type for this but we really have one prop at the moment anyway so let's just do data and that will be uh what was it session eyes and we'll make that a that and we're going to deconstruct here so we'll get that data back okay so just I guess yeah let's let's follow what um I was going to get co-pilot to just scaff me out a basic component just so we can see if this works um oh it's not going to work because um that is group ID and uh we'll just do say group name just for the moment and then we need to import that component into here save that there we go we are getting we're getting under the way we're starting to build out a UI we do better though from a UI standpoint than just some bull points like this we're going to create I kind of want like a like some kind of a header you can click on to navigate between the different days and then as you navigate we're going to change the sessions that are listed so we'll delete off our stub code that we got from GitHub Copart and I'm going to add a tab list control from um fluent UI so we'll add our tab list and inside of this we can have uh tabs uh actually the tabs are going to be made up from uh mapping through our sessiz data now it is called tab not TBL list. item again gab copilot is is making it's trying to make assumptions based off of what it thinks the data looks like but that's not quite what it is going to be uh so we'll just give it some help there uh so we're going to give it a group ID we're going to need to oh I have just done something let's just reset zoom and then we'll Zoom back in again uh because I pressed a button on my keyboard and things got a little bit freaky uh value we need to provide a value which is going to be um uh do we need a value I don't know if we need a value yet um oh uh tab yep and then we're going to say day and actually we'll grab I and we'll say day and we'll do instead of session. title which does exist we'll do I i+ one okay and okay we're missing we're missing a value from there so let's say the value can be the session it yeah let's just let's call it that uh dot dot group ID there we go okay let's save that and I have not got uh I've got a closed squiggle there oh I forgot to close the tabl list components there we go that's what it's unhappy about that there we go nice little heading we see as we hover across them I'm getting a little underline indicating where we're at and that's working cool but we don't actually know which day we're on um the value is there it's tracked so what I'm going to add is a way that we can like when we click on that we can track the value so we'll add some more State we'll do uh the selected dat we've got selected day and we'll do set selected day and we'll just initialize that with the current no not group ID we'll just put the whole group in there just passing memory references around so that can be easy and then the value can be that and then we'll do selected um set it is no I know we don't need to change that do we um active no trying to remember if I needed to set something sorry to indicate that this is the current selected tab but no that that's tracked internally with inside of the TBL list component um but yeah so there we go reload that okay done um and I'm just going to check by notes because yep that looks all good make sure I am returning this corrected oh I need to specify which is the selected value on the tab list um so that we can control this initially on Startup and we're like selected where properly controlling is it will be H selected selected select it should be selected day not select day selected day because that sounds more grammatically correct there we go okay now now we now we're not clicking around because we're not tracking which is the select the day so what we're going to add is an onclick Handler here and we will then just say um set selected day and we'll pass in the uh we'll pass in session night which is the current selected dat and I accidentally Clos the par parentheses too soon all right there we go our Tabs are working again and we're transitioning across days now all we've got to do is render out our list of sessions so for that I'm going to create a new session list component and we'll pass through the sessions that seems good uh we'll export const session list which will just save that as session list. TSX and then that can have what do we call that we call that sessions and then that will be a sessions array and from here we will um we'll return something in a moment let's just return an empty component while have a bit of a think about what we're going to return let's just get our compiler errors all fixed and all of our JavaScript runtime errors return it didn't like doesn't like that empty component because it needs to have children inside of it um okay what we're going to do is I'm going to create an inner component with inside of this uh so we can do sessions. map and then we'll pass through the session and we'll create a session component that will take the current session yeah that looks pretty good now let's create that session component uh uh we'll create a con session and then that is going to receive those values and we'll return our open and close react fragment and then we will do do a divd off that and then inside of here we'll [Music] have not a date but we will use a we use a H2 instead of a H1 okay let's see I've got a whole bunch of red squigglies we got to figure out what all of these red squigglies are representing okay so we are concession something thinks there is a something is returning a bullion H that's interesting concession equals that turn oh hang on a sec did I did I rename that file badly let's ah it thinks it's a typescript file not a typescript react component file so let's fix that that's probably going to sort out here we go okay session dot title session title session Des oh look at that fix that up nicely uh and then the last thing we're going to add is our list of speakers which will be session. speakers dot join and then we'll do that and squiggle there we go oops speakers dot map uh yeah map uh S and S dot name there we go okay there we go now that's looking better um I check the Vier in between these just so it's clearly it's clearly indicated where each session break is there we go look at that click ah it's working we're navigating between tabs we're seeing different data it sound it's it's looking pretty good that's a it's not not bad for a good little scaffold up of a UI over our our react application there but we're not quite done yet we've only done read operations so far we still need to be able to do some right operations because there's not going to be well a a session selector if we've got no way to select sessions um so for this we're going to add a couple we're going to add a button to this page uh and when you click on the button it's going to then allow you to um add the session to your watch list or if you already added it it will remove it from the watch list so let's start by adding some but actually I just realize there's one bit of data that's missing here I don't know when the sessions are actually on let's add that one in We'll add in a p add in a time element and then we're going to add in um actually going to grab our uh some stuff that I wrote earlier for working with time zones because that is a little bit more verose than uh I feel like typing out at this n not going to need that and we're not gonna need that okay so what we're using is a JavaScript library called DJs um and then DJs has a bunch of plugins for working with multiple time zones and stuff like that so I'm going to bring in localize format because we're going to localize it to your current um time zone um the time zone extension and then UTC created a couple of functions such as format um so the D the dates that are in the data are in PST or specific Standard time which is redond time and then so we're going to be able to we're going to format that way and then we're going to format time and we're going to allow you to provide in a like an override for the time zone you want to use and then adding a local time zone and we're just using um DJs TZ guest to try and figure out what time zone you're currently in to then display that out now let's render out all that uh uh time data uh which is possibly around about that information so we're going to format date with um oh hang on a sec it thinks that's a date it's actually going to be a string we're not deserializing so let's just make that a string all right so starts that and then we will send that through to uh format oh whoops and then we will do hyphen and Enz and then just to indicate this is PSD I'm going to put PST line on the end okay so that is um that session is 14th November 2023 at 8: am to 9:00 am PST that's that's correct according to the net um conf website but it is well it's not really helpful for me I'm in Sydney so while I can see that it's PSTA what time is that for me let's let's duplicate this chunk of code and we'll pass in the local time zone so we're going to pass in the local time zone and we'll pass that across to our start at and then we'll pass that through to the end and then we're going to render that out here be local time zone okay there we go that is 3: to 4: a.m. Sydney time probably not going to get up for it and watch the recording of that one I think um let's get rid of the like theay prefix so we'll do a split on slash and we're going to just take the uh on the Slash and we're going to just take the second part of that there we go so Sydney time that is going to be 3 to 4 a.m. excellent I'm liking I'm liking the way this UI is working now but it's enough youi let's go back to the back end then let's build out those additional apis we're going to need so that we can um read the sessions that you selected and we'll write sele selected sessions so we'll come back into our program.cs and I'm going to create a new route here so we're going to do string uh selections path and that can go into Data selections that sounds good and then we're going to create a yep that um that app. MapIt again because we want to H to be get to get the selections um actually I'm going to make it slash user selection just so I know know that it's kind of scoped to a user operation uh we'll open the file stream for read we'll then deserialize that but we're just going to re deize that as a string because we'll just store the IDS of the session we don't need to store more information than that uh and we'll return the selections now we might not have had any selections yet so we probably want to check to make sure the file exists so if the file doesn't exist we will return um we'll just return an empty array because that's that's fine we don't actually need anything more than that oops oh didn't uh there we go so we'll just return an EMP array if there isn't one exist um I'm just using oh what I'm using here is the um C uh uh object sorry collection literal syntax and that's why I'm just doing like open and close square brackets to indicate that I'm going to return an array that's part of cop 13 that is in preview at least at the time of recording uh and then now I need to do a uh a map post sure let's see what did co-pilot generate for me this time I feel like I'm cheating a little bit here um we will write all to text that path of that selection file yep now we don't need to worry about whether the file exists or not when we're doing the right because it will generate that file if it doesn't exist already um and we're going to receive an array of strings which is the all the selections so we just be really simplistic here we're just always going to overwrite the existing selection set done all right let's restart our server again because the back end is all completed we can build out our new UI to work with that we can sorry more accurately we'll extend our UI to work with that so we're going to need to add a um we'll say a new um hook here we'll do const selections and we'll do set selections and that can be an empty string array done now we need to get those selections back when we're doing it so I'm going to do that kind of as part of this effect here so on the initial load so instead of doing an await await fetch I I want to do these requests at the same time so I'm using I'm going to use promise. all and then we're going to pass in an array of awaitable operation so that initial fetch there now this is then going to return an array square bracket close that and then parentheses closes that now this is going to return an array so I will use um array destructuring to generate those resp response and we'll change this to be uh what's that sessions response just to make sure it's better indicated of what it's actually doing now we'll create a new fetch uh fetch to API user selections and we'll also pass in the abort controller so that like if we abort one we abort both and then we will unpack that as uh selections response and then uh that can be let's rename that one as well that can be uh [Music] sessions data and then we will add uh selections data and then set selections Al righty let's have a look at our debugger here reload that let's check our fetch in there we go we'll see that it attempted to load those two initially but they both got cancelled and then we've just got back what we wanted fantastic um [Music] now we're going to need a way obviously to to modify those selections but um so I'm going to create a couple little helper functions that will pass down to our child components we'll create a new one called add selection and that will take a uh selection sorry session ID and that can be a string and then that will'll just call um set selections and then this time we're going to take the um current data and then we will do a array structuring of that so in this case I because the hooks could like because we could like click on multiple buttons um in quick succession and the react con currency engine might not have completed um we're going to just uh use the Callback approach to setting state so that it will then create a a stack of um of State mutations to execute rather than just potentially modifying this inside of the closure scope that has um that is incorrect uh we'll we'll just always use the um the current we do array D structuring We'll add that to the array and then we'll add that session to the end now we're going to add a remove remove selection and we will just yep use an array filter and again we're going to use that off the um the current selections there just say filter we're going to find all in the current set that aren't matching the session ID easy let's now pass this one into our session component we're going to add we're going to pass through the three bits of props so we'll pass through selections selections add selection now this is going to have some red squiggles for the moment because we haven't passed we haven't added these props to our component but we'll do that shortly remove selection remove selection and I just realized I spel that incorrectly cool uh let's come into our session actually because I'm going to pass this down a couple of times we'll pass that in there we add that to the session list and then finally we'll go to session list which we pass it through to sessions themselves so it's going to Cascade down a few times but we'll worry about that um we'll we'll populate that out next okay so we'll have selections which is going to be a string array we'll we have the add selection which is going to be a dispatch function so dispatch is a type that is provided by react um so it's essentially a function that takes a value and returns a void which is kind of what we defined there so I'm just going to use that um type rather than creating a complex type signature for this we'll do remove selection and that will also be a dispatch of string okay let's add these to our child component as our definitions go ahead we need to import that on our react import statement Tada there we go and last thing is to actually grab selections uh add selection and remove selection there we go I'll grab these add that to here and we'll add that to here okay everything is cascading down nicely we need to add the but we need to add the button obviously first we need to know is this selected so is this session is the current session that we're rendering selected so is that in is the ID of this session in the array of selection selected sessions uh and then we will say is selected oh did I call it is Select okay I've called it is select um we'll create a button component from fluent UI and then let's add a um let's make the appearance so if it is selected we're going to make this a secondary button appearance and then uh what's it say uh if yep the on click is going to be remove and then we'll close the button out there whoops uh I tried to create nested buttons there we go and then we're going to say uh remove from watch list okay oops go close my curly bracket I think uh yep and then I need to do the same again which will be ads and we'll say add to watch list slash [Music] button and then close bracket close squiggle and we'll see did I get everything ah looks it's even appeared everything looks great now it's not quite looking how I want let's grab in I'm going to grab in a icon fluent UI supports um icon so I'm going to add a little icon onto this one here go oh I need to import that component though there we go we've added our icon there we go um how does this look full screen it's hard up against that that's not what I want let's let's add some developer developer styling so we're going to add style and we are going to say float right I have a developer and this is now I do CSS hey look it it's still not looking great because it's such a tiny screen but it looks better on the big screen there everything's Flo is right maybe put a bit of margin on the bottom of that so that it fits uh so it sits down there um dock that to the right correctly uh let's just say style margin margin there we go action margin bottom we'll say npx oh actually no not margin I want padding bottom there we go and did that work well maybe I do want margin bottom [Music] margin let's see is that working is that looking better in full screen no uh pop to the right style margin bottom did I put that on the right element yeah let me let me refer to my notes um reckons padding bottom should have all should have been needed pading bottom um okay anyway we we can make it look prettier later on that's the the functionality let's make it let's make it functional first and then we'll make it look pretty um okay uh yeah anyway that's okay so now now that's done um we're we've got local St working so as we click we can do that but if I reload the page we'll lose that session um being added to our thing because added to our watch list because well I haven't persisted that back to our back end lastly we're going to add a use effect hook here and this um we'll follow kind of that same pattern as before we'll do save selections excellent but we're going to need to pass in our D selections as a um as a thing here and then we're going to also have our um aort controller we're going to pass in our bort controller and we'll pass the signal and then last but not least we'll return the abort controller save that excellent okay so have a look does this work yep um okay we'll add to watch list that's looking good we see we had a selection down here where we sent that up and we we don't get any response back from that so there's no that but there we go we've added that one to our watch list reload and it's been removed from the watch list so close so close um okay let's let's have a look what's happened here added to our watch list we can see that it's there now let's reload the page and we'll have a look so it's it's gone um oh we we are doing some Co we're we're sending an empty array up that's that's not right now well I mean it's not what we want but it's actually what we kind of expect the reason that that's happening is because we're not telling it when to save selection we're just whenever the session array changes we're going to send send that up so what's happening is that we well we create an empty array of um of selections so we send that up which then causes the mutation which then um we initially get back that selected list but we then immediately overwrite it um and we rewrite the data so that's kind of problematic instead what we want to do is um if the session uh so if we have loaded then we want to do save selections just to this kind of race condition that we're hitting but we're also going to have to add data load State into our use effect hook there now this is not a perfect solution I will be um honest on that there like we can do some improvements in know avoiding these race conditions but from a from the scale of this kind of an application this will work quite well all right so um that reloaded yep add to watch list day two We'll add to watch list and now let's reload and F cross yes we've received that correctly that is on the watch list this one's on the watch list and this one here is not because we hadn't added that one there well that is that that's I I think that's not bad for nearly an hours worth of work um now there's obviously more you can do to this application but we're just com we're just about coming to the end of what we've got time for today um an exercise that might be um fun for you to continue on with this is inside of our session eyes list here you could add a new tab say a tab and then this one we'll say uh not call it all say selected sessions and then we'll say or actually watch list call it yeah we'll call the value watch list I have a capital world no without Capital World okay anyway but there you go you could have like the watch list there and you could have that selected and then it will only show the sessions that are in your watch list now for doing that you would have to work out have how are you how are you pulling that um working with that JavaScript data and and loading up what will essentially be like a virtual day because that day doesn't exist in our current data set but like I said could be something um it could be something fun to experiment with uh in your own time like I said we are coming towards the end of uh today's session and just as we wrap up let me bring up our resources slides and come to the right screen um thank you for joining me for for today's um student Z session around building with aspet minimal API and uh single page applications in this case use react you can translate that across to any other front-end UI framework uh if you want to check out some of the other sessions we've got on uh the Student Zone this year you'll find all their um resources at aka.ms NETCOM 23 student repo you'll find their source code and links to their recordings in there and we also have some others um links here that uh could be some addition learnings if you want to follow one of those such as um some a c certification that we released a couple of months ago some beginner videos around Net and obviously check out all the sessions that are happening at NETCOM for this year you'll find those at aka.ms NETCOM 23- Student Zone find other Student Zone sessions plus the rest of the conference that's happening my name's Aaron pal thank you for joining me today I hope you've enjoyed it and I look forward to seeing you next time [Music]
Info
Channel: dotnet
Views: 5,673
Rating: undefined out of 5
Keywords: .NET
Id: v84VOudElNI
Channel Id: undefined
Length: 60min 34sec (3634 seconds)
Published: Wed Dec 13 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.