Intro to In-Memory Caching in C#

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
application performance is important just because your application works in development does not mean it will work well once hundreds of people start using it one key area to look at is data access talking to your database can be expensive especially when the data might not change that often that's where caching comes in we can cache that data in a number of ways so we do not need to keep going back to the database for it in this video we're going to look at one of the simplest caching mechanisms in.net called in-memory caching we will create an application without caching observe the performance and then see how how caching can improve our performance we'll also discuss the best practices when using in-memory caching now this is the first video you watched of mine my name is tim corey and it's my goal to make learning c-sharp easier i provide videos here twice a week on youtube to help you grow as a developer i also have a full set of training courses on i am tim cory in a podcast titled dev questions i encourage you to check out all the resources that i have to offer now this video as of most of my videos is going to create some source code if you'd like to copy the source code use the link in the description so let's go over to visual studio i'm going to create a new project now this most easily works with web projects because they already have built-in dependency injection we'll go ahead and use that in fact we're going to create a blazer server application let's call this caching example and caching example app and we'll hit next and we're going to use net 6 we're not going to use authentication we are going to use https we're not going to enable docker hit create and this is just our standard application we're going to start ripping as right away but first let's create a new class library so right click on the solution and say add new project where i create class library hit next and we'll call this our data access library and.net 6. i'm going to create class library here let's delete class 1 and create a class library because the fact that i do want to show off how it worked differently a little differently inside a class library as opposed to just inside blazer itself so we're going to create a new class and this is a very much a demo app so we're not going to go through all the the normal procedures of folders and all the rest we'll just create everything right in the root it's fine this is demo so let's create employee class employee model and make it public where i say prop string first name prop string last name so all that's doing is creating a first and last name really simple model for us to work with and the idea here is this is going to hold an employee's information again there's a lot more to employee than just a first and last name but that's all we need to worry about with this demo next up let's create a class so say add class and we'll call this our sample data access this is going to be a public this is going to simulate the idea of us talking to a database we're not going to talk to a database because that's not the point of this video so let's create a public list of employee model and nope intel code got ahead of us there and where i say get employees so we're going to create a list of employee model and we'll call this output and we'll say equals new that creates a new instance of it and final return output now in between here let's actually put some sample data in place so output.add [Music] new intellicode wants to put the new employee model but within the new syntax i can just say new like this make it shorter and it's already long enough so i'm gonna make it shorter like this that way it's just it doesn't go off the edge of my screen i'll create up more of these and sue and jane and storm and let's go with jones okay so now we have us get employees it returns three employees but we want to simulate the idea that it's expensive now in a real data access scenario maybe you're accessing a thousand records or ten thousand records something larger where or maybe it's across the network talking api whatever it's gonna be you'll probably have some sort of delay now for us what i'm gonna do is i'm going to simulate a delay of three seconds just to show off the fact that it's it's operating slowly now obviously if your data access takes three seconds you might want to address that in some way but for our demo we're just going to say thread.sleep and we'll sleep for 3000 milliseconds so that's going to delay the output returning for three full seconds and that's pretty much our entire demo code to start with so we have us get employees it's going to return a list of employees and then from there we're going to [Music] get those employees over on the other side so for that we need to first of all right click on dependencies for our caching example say add project reference reference our library references go one way so you cannot reference your caching example down your data access library don't do that it's only one direction and then down here in program.cs what we're going to do is we're going to add add a reference to that so we're going to say build.service services dot add transient and we're going to say sample data access control dot to add that using statement like so now i didn't create an interface for this normally i would with my data access i'm sorry dependency injection but um i'm not going to for this again we're trying to keep it simple so with our data access now added we can go and talk to that on a page let's go to pages let's go to fetch data page so if we were to run this application the fetch data page is the weather page in fact it says here with our forecast that's the page title let's call this employee directory and we'll call a same use the same thing for the h1 tag here employee directory let's get rid of the injections here let's get rid of everything basically all the sample code right down here get rid of it all and even get rid of this so we're starting over on the employee directory the only thing we're keeping is basically the page which is fetch data and i changed these two things this by the way is a new feature and what it does it changes the um the title in your tab of your browser really cool thing so it's actually talking to the title in the header of your individual page so now with our code we want to say oops let's add a import statement first go to imports and we're going to say at using and our data access library what that will do is it allows us to not have to add a using statement here in order to say something like list of employee model employees okay so we have to add a using for our data access library now that we're here let's go ahead and say protected override on initialized we don't need async because you're not making an async call now what on-initialize does is it calls every time the page is loaded this gets called and so you can say hey give me some data so in this case we're going to say employees equals data which we don't have yet let's grab data so up here where i say inject and sample data access we'll call it data so employees equals data dot get employees all right so what we do here well we injected this from dependency injection we gave a name of data we're now calling that in our uninitialized async we're getting those employees we're putting them into the employees object which is right here now up in our code where i say at if employees is not null then we're going to do a for each and we'll say var e in employees and then inside here let's just create h3 records that's fine just for the demo e dash first name space add e dash last name now using the the at symbol here um because we're mixing both html and c sharp code so whenever we're mixing we have to then we've gone to html here therefore we have to say okay now it's time for c sharp code in that space we have to go back to call me add again because again thinking is html so that's the difference um i don't think we need one of the four each here because the fact that it's right inside the if statement if we do we'll store it on so let's see it's work this should be all we need to get our application up and running let's see if it actually loads it was a good first time there we go and the page is loaded we can go to the counter the counter works let's go to fetch data wait for it wait for it wait for it there we go so fetch data works but it's slow we go home boom right there counter right there i just clicked and i'm waiting waiting wait there we go now the page loads not a great experience but there are things we can do to get better right we could probably make this an asynchronous call right now it's a synchronous call cool let's go ahead and do that so let's go over to our sample data access and we'll say okay this is all synchronous let's make it asynchronous in fact let's let's copy this so that you have an example of each so public list of employee model call it gets employees async and we should make this an async task of type employee model and we'll do the same thing we're doing here only we're going to say instead of thread.sleep we're going to say await task dot delay it's a similar process but it's actually making it it's an asynchronous await i'm sorry it's an asynchronous call that's awaiting so therefore you can wait on this it's going to stop doing work here but it will continue to allow the ui thread to interact so we now have an asynchronous call we can come back over to our employees page let's comment this out and we're going to say protected override on initialized async we can get rid of the starter code here and we can say async task and we'll say employees equals await data dot get employees async so now i made it asynchronous cool that shouldn't lock up the ui so let's run this again and we'll see if this makes a difference in how our page loads so counter fetch data oh the page loaded it says employee directory but then waited to show how this show up okay so we can make a slight improvement here where we have if employees is not null we can say else and have an h2 that says loading actually it should be probably in h3 because both these are h3s so let's run this again and now once you go to that page it should say hey you're loading you're not done there there you go we're loading loading loading there we go now there's our records so it's still taking just as long to get the data but at least it's showing us a loading bar but that's an expensive call and imagine if we wanted to show the employee directory quite often you don't want people to wait around for the employees if you can help it and hopefully your employee directory isn't changing every minute so if this was showing up on every page or this was a common thing maybe you're calling it you know once twice three times a minute uh per person that would be very very expensive well there's other ways to do this and one of the ways where i'll look at is in memory caching so this employee list does not change that often therefore we can say hey let's cache this so that we don't have to always [Music] load it from the from the database we can pull it from our own memory to do that let's start by going to program.cs in our blazer project down here in the services section we can say builder dot services dot add memory cache okay it's already built in add memory cache all we have to do there and what this will do is it's going to add caching for us and this is going to create a singleton for us so that we can call this across all of our uh our different instances which means that you don't want to put stuff in here that you allow anybody to have access to if they're not allowed to so for instance if i were to cash um a person's social security number i wouldn't want to have any else get access to that so i still want to protect it in the same way i protect the data access call for that person's social security number but for shared things especially for things like the list of employees that's we can share that across callers which means that we can cache that data once and then have everyone use it so let's go back to our um our sample data access where i create a new method so now you have a sample of each public async task list of employee model like so get employees uh let's see call it cashed or cash because this will return the cash employees asynchronously this is just a name to tell us the difference between the three of these it's not necessarily a trend i would use or a key i'm not saying this is this is like async you don't have to tag your methods as cache capable okay just be clear there so we're going to create something very similar here so we'll create a list of employee model called output i'm not going to instantiate yet though i will return output which will break right now because it's returning a a non-instance a null but what i'm going to do is i want to grab the cached version of this list to do that i need to be able to talk to the cache so i'll create a constructor and i'm going to say in the constructor i'm going to ask dependency injection for an i memory which i can't get access to yet whoops i've got to add one more thing and that is and this is why i did a class library here over in our program.cs no problem add um add memory cache it knows where that is cool but over our class library oops over here it doesn't know about memory cache so we have to add that ourselves so right click and say manage to get packages and we're going to say microsoft.extensions.caching.memory so if it does not exist in your particular project type just go ahead and add it this is a nuget package that's from microsoft hit install and okay once it's installed now we can say i memory cache like so and then we have to do a control dot to add the missing using statement for microsoft.extensions.caching.memory once we do that we can say memory cache now i'm going to ctrl dot here and create and assign a field like so now yours might do the same thing it might say this memory cache equals memory cache and not have the underscore here if you i've got an upcoming uh 10 minute training on how to change this to use this format but if you want this format then just copy it manually until you watch that 10-minute training okay this is just a shortcut it's all it's doing to assign this to a private read-only version called underscore memory cache so now down here i can start working on my output i can say output equals whoops memory cache dot get i want to have a list of employee model like so and i want to pass in a key now the key is something that this is a key value pair so therefore you have to remember the name of the key i'm going to call this uh employees i could uh create a variable that holds this that's fine that's probably what i do in a real application but for this this works so it's going to find the employees in the cash now you're saying but but how tim because there is nothing cashed yet you're right there is nothing cached which means we're going to have an if whereas say output is null so if output's null then we don't have any data from the cache therefore what we're going to do is i'm going to grab from here notice i'm grabbing the output equals new i'm going to grab all the way down to here including the task.delay okay so now i have instantiated the output i have added the three items and i have delayed just like the above async that way we're not comparing apples to oranges this is an apples to apples comparison if we create the new entry but there's one last important step here if you do not find it in the cache and that is if you want to find in the cache ever you'll want to say memory cache dot set employees output now it could be down here but i do not want to be this is important at the very end you need to give a time span i'm going to say from minutes one what this does let me unpin as you can see the whole thing what this does is it says okay i want you to take that output i just created which took those three seconds i want you to put that into the cash named employees but i only want this cash to live for one minute this is important because in-memory caching is something you have to be careful about this is one of those um tim's gonna make sure that you're clear on this sections so memory caching is not limited now where is it storing it the clue is in the name memory so if you put too much data in your memory cache you will run out of memory that would be a problem now memory caching does not have a idea of limiting based upon the number of kilobytes in your memory or things like that you can limit the number of things in memory but it's more about limiting the number of objects or saying this many whatevers in my memory and you get to choose those numbers it's not a a um a size as far as kilobytes megabytes and so on so it's a little more delicate and you do have to be careful the the caching can be used to a higher degree for example you can say what the priority of this cache is compared to other things that way if the system starts running out of memory it will take away the older things and the lower priority things and the things that are expired before it takes away your high priority thing but i don't find that terribly useful because i don't intend to ever use memory caching that heavily instead i want to use memory caching for things that i know aren't going to be too strenuous in the memory and that will actually make my memory lighter because i'm not continually calling for those new records and creating new instances of the data for instance let's just pretend that this output list here is a hundred objects long well if i'm call if every person calls this every time i load the application that's creating a hundred new objects every time any person creates these objects instead i'm taking the hundred objects storing them once in memory and then having everybody talk to them everybody see them therefore it's more efficient as opposed to what i was doing so you can definitely take advantage of that way but don't just say hey i might need these you know million records i'm going to throw some cash just in case i need 10 of those well that's going to affect your memory negatively so don't do that but the other thing is that you don't want to have things in your mem your cash indefinitely because the fact they may get old for instance yes employees do leave new employees do come how how often do you want how old you want this data to be so for an employee list you know what really it could last a full day not a problem because that list isn't changing so yeah not a problem to last a full day for our case we're going to say a minute and and a lot of times you want a cache that lasts a short period of time like that maybe you know if the person is bouncing back and forth they're gonna see this list a hundred times but it's gonna be a hundred times in ten minutes well then maybe you cached it for the ten minute period and they only ever load the list once so be careful how much data you put in the cache and be careful how long you let it sit there what this will do is after a minutes time it's going to tell a system yeah you can get rid of me which is another important point here is you have to you have to count on the data not being there you have to prepare for it not to be there this is why i don't just say hey get the cash values in return i say hey get the cash values but if it's no let's go ahead and go to the database get the real values and then cache those values for the next call all right so i'm trying to be very clear here use caching appropriately do not abuse it otherwise you're abusing your own server and making your life worse not better there's a balancing act to hit here there is not one clear cut well this is better than the other in caching just like most other things in development it does depend on your circumstances just being clear though you need to be careful okay so with this caching in place now we're gonna talk to the cache the first time it'll be empty therefore we'll do the same thing essentially as what we're doing up here but the last step is here is we're gonna save that cache next time we're going to find it in cash it's not going to be null therefore just go ahead and return let's see us in action by going back to our um oops our fetch data page and instead of get employees async we're going to get employees cash it's still asynchronous but this is going to talk to the cash let's run this application make sure it runs we haven't missed something wait for it there we go so counter still works home still works let's go to fetch data it's loading and it's done okay let's go to counter back to fetch data it's already done okay you see the difference there i can go back and forth all i want and that page is done i have to wait for it again now if i wait a full minute then it's going to go back to the cache again and say oh you know what you're you're no longer there therefore i have to go back to the quote unquote database and get the data let's just see if we can't wait for that to happen once it does click over i have i haven't been tracking how long it is but once it does click over it's gonna go back to that idea of loading before it you know shows us our data so not exactly a huge mind-blowing thing but i did want to show you that in fact it does happen um wait for it wait for it oh by the way if i go to a new instance let me pull up a new in private instance um let me just make sure the cache is still here oh there it goes it's loading again there we go so now let's grab this url let's go to our our new in private mode and we'll paste and go it loads right there there's no delay on that because the fact that it cached once as a singleton which means that any other caller still has access to that cache again we wouldn't want to cache sensitive data in the um in the instance where everyone can have access that same instance but if we let's say limited by employee id and only allowed an employee to grab their own employee ids worth of stuff then that could work but just be careful of caching sensitive data i tend to avoid it whenever possible but instead things like this that are essentially viewed things that everyone has access to maybe another thing is for whatever reason you have the months of the year in your database now you don't need to but let's just say you did well then you could cache that data in a really long time span because that's just something that everybody is going to see at the same time is not going to change ever hopefully so with that then you can use cash to make your your application much much faster now to be clear when i shut this down and i load it back up that cache is gone because it's an in memory cache this is simulating what happens if you restart your web server so if i restart web server this list is no longer in memory because it's an in memory cache therefore you have to load all your things up again which means if you're doing a lot of caching on things that come from the database but maybe aren't um aren't updated a lot like your employee directory and like a uh a few drop-down lists that come from a database but um you know the same all the time so you cache those your initial performance your applications be a little bit slower because the fact is talking to the database the first time for all of those things where you might want to load your application up once after you deploy it to b you'd be the one that loads all those caches once they're cached then the next visitors have an instantaneous response like i'm seeing here okay so that's caching that's how it works it's really not hard it's the idea that you just say get and set the key thing here is set is make sure that you have a time span here that is appropriate for the element you're storing now you can use instead of the time span here you can use cache options and have a lot more granularity there's things like a sliding scale so you can say hey if no one accesses this cache for five minutes then go ahead and refresh it but there's also an absolute time and you want to set both if you set one so if you set the sliding scale then go ahead and set the absolute as well the absolute is it doesn't matter if you've all been accessing this cache continually after an hour this cache is invalid and refresh it so there's options like that and there's others you can look at as well but again i don't get that deep into memory caching because if i'm being that precise and that in-depth on my caching i'm going to go to another step up like let's say redis where i've covered that before ras is a great caching mechanism for making your your database load lighter making your application faster and at the same time not overburdening your memory with in-memory caching so this is there's different levels here i would say if you're going to do simple things the in-memory caching is the way to go it's fast it's powerful and if you don't abuse it it's great if you start abusing it yes like anything else it's going to make your life miserable but really it should because you're abusing the thing so with that that's memory caching check it out try it in a web application see how it works it does work in desktop applications and other you just have to do a little bit more work in order to either my recommendation is get it in a dependency injection so you have to get a little bit more work in order to get this going um but once you do then you're you're golden you can use it just like you would in a web application but in a desktop application so with that let me know down in the comments if you have any questions or thoughts i'll try and get to as many as possible i always can't respond to every comment but i do try at least look through them and see if there's any questions i need to answer on a future video or if i can answer something really quickly all right thanks for watching and as always i am tim corey you
Info
Channel: IAmTimCorey
Views: 53,635
Rating: undefined out of 5
Keywords: .net, C#, Visual Studio, code, programming, tutorial, training, how to, tim corey, C# course, C# training, C# tutorial, .net core, vs2022, .net 6, in-memory caching, c# caching, c# memory caching, asp.net core, cache in asp.net core, blazor, c# blazor
Id: 2jj2wH60QuE
Channel Id: undefined
Length: 33min 55sec (2035 seconds)
Published: Mon Dec 20 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.