Distributed Caching In ASP.NET Core With Redis | Introduction

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi everyone my name is Milan and in today's video I'm going to show you how you can Implement caching in your asp.net core web apis using redis we're going to be running redis inside of a Docker container and I'm going to show you how you can connect to this redis instance and use it to implement caching in your application let's jump straight into the code and I'll show you how we can do this we're going to briefly take a look at the cache member repository implementation that I implemented in a previous video if you didn't watch that video yet where I discussed The Decorator pattern I suggest that you take a look at that video first and then come back to this one the link is going to pop up on the screen right over here inside of this cache member repository implementation we are using the memory cache that is available in asp.net core and what we're going to do now is replace this memory cache with an instance that can communicate with redis and we're going to implement distributed caching the proper way I'm going to add a new nougat package to our application and I'm going to type in redis here in the search bar and the library that we are looking for is the Microsoft extensions caching stack exchange redis so I'm going to go ahead and install it as you can see here in the description this nougat package contains the implementation for I distributed cache using redis let's go ahead and configure our distributed cache what we need to do is add a new service and there's an extension method that we need to call it's called add stack exchange reddis cache and we need to provide a setup action to configure our connection string to redis I'm going to Define an action to configure our red disconnection so I'm going to say redis options and let's define a Lambda method what we want to set on the redis options is the configuration string and this is supposed to be the connection string to our redis instance I'm not going to hard code this value I'm going to take it from our connection strings in the configuration so I'm going to say connection and I'm going to access Builder configuration call the getconnection string method on the configuration and I'm going to pass in redis as the connection string name and we're going to use this connection as the connection string value I need to define the actual connection string value and I'm going to do that in the app settings.json file inside of the connection strings I'm going to add a new value for redis and by default since we're going to be running redis inside of a Docker container the connection string is going to be localhost and the port is going to be 6379 so this takes care of our redis connection string this value right here is going to be provided to our configuration method over here and that's going to take care of connecting to our redis instance now let's go back to our cache member repository we're going to replace the I memory cache interface here with something that can communicate to our redis instance what we're going to need here is an instance of I distributed cache I'm going to name it distributed cache and I'm going to inject the I distributed cache instead of the memory cache let me just fix the setup here and I'm going to rename this memory cache here to distributed cache asp.net core is going to provide us an implementation of I distributed cache using the stack exchange redis Library which comes from the folks from stack Overflow we're going to be using this distributed cache to implement caching using redis let's get rid of the old implementation that we had here that was using the memory cache and implement the new one that is going to be using our distributed cache I'm going to make the method asynchronous and let's see what we have access to on the distributed cache that could be useful for us so if you take a look there is the get string async method right here which is going to get the value for the given key in this value we're going to serialize our object that we're storing in the cache and when we are retrieving from the cache we need to deserialize this value into a proper object in this case the object that we are converting to and from Json is going to be our member instance the first step that we need is to get the value for this key from our redis cache or rather from our distributed cache and see if that value exists if it does exist we have a cache hit and we can return the cache value from this method so let's go ahead and Implement that I'm going to say string cached member and we're going to call distributed cache get string async and I'm going to pass in the key and the cancellation token as the arguments now I need to check if the cached member string is null or empty which means we don't have a cached value so let's go ahead and do that if string is null or empty cached member this means that we have a cache Miss so we need to go to the database and get our member from the database let's go ahead and do that I'm going to save our member is await and the way that we are going to get the member from the database is by calling the decorated member repository here and the get by ID method and we're going to pass in the ID and the cancellation token let's make the member variable type explicit now that we have our member we first need to check if the member instance is null if it is null we don't want to Cache anything because there's no point and we're just going to return the member from this method which is going to return null if the member is not null we want to Cache it inside of redis so that we can reuse it in subsequent requests to do that I'm going to call the distributed cache set string async method and what this method accepts is the key and the value that we are storing for that key we already have the key defined for the value we're going to serialize Our member object for that I'm going to use the Newton soft Json library and I'm going to call serialize object and pass in Our member and I'm going to pass in the cancellation token this is going to take care of caching Our member inside of redis and that key is going to be present and available for us the next time that this method is executed now that we have successfully cached the member inside of redis we can return the member instance from this method this takes care of the case when the cached value is not present in redis and now we need to tackle the case when the cached member is not null or empty meaning we did get something returned from redis what we have to do is we need to deserialize Our member object from Json so I'm going to create a new member instance and notice that this is going to conflict with the variable that we have defined here so what I'm going to do is I'm going to take this variable define it here and then we're going to set the value for the member variable in both of the branches I need to get rid of this VAR here and I'm going to use Json convert again to deserialize the cached member string that I just fetched from redis so I'm going to say this serialized object and I'm going to specify member as a generic argument and we're going to specify the cached member string that we got from our distributed cache after we deserialize the member we can just return it from the method so this is how our implementation using redis is going to look like we're first going to try to get the cached value using the key if the cached value is missing we're going to access the database and try to get the member from the database and if the member is not null meaning it was found in the database we're going to Cache that value so that it's present in redis for subsequent request if the cache value was present we're going to get here where we need to deserialize the Json into a member instance and then return that instance so this implementation that I have right here is not going to work right away if I go to the member class definition you can see that the constructors here are private I don't want to decorate them with the Json Constructor attribute to let mutants of Json know which Constructor to use so I'm going to go back to our cache member repository and I'm going to specify another argument here to the the serialize object method we need to specify a new instance of Json serializer settings so let's go ahead and create one and on it I want to set the Constructor handling property and the value that I need is allow non-public default Constructor what this is going to do is tell Newtons of Json to look for a non-public default Constructor which is going to be our private parameter-less Constructor that we have defined inside of the member class let's try to run this implementation and see if it works before I run our web API I need to start our Docker instance to start our Docker instance I'm going to run this command inside of the console I'm going to open up the 6379 Port that I specified in my connection string and I'm specifying the redis image here as the container that I want to spin up so I'm going to press enter here and this is going to spin up a new container running redis on this port and now we can start up our application and see how caching with redis Works in action I'm going to send a get request to our API from Postman we are hitting the get member by ID endpoint which is going to call our cache member repository where I just set the breakpoint so we hit the breakpoint inside of the cached member repository and we're going to slowly walk through this method and see what is going on the first thing that we do is we create a cache key for storing the cached value inside of redis then we are going to use this key to try to get the cache value from the redis instance and as you can see the value that we get back is null which means we have a cache Miss because we did not cache the value yet so we are going to go inside of our if block and get the member from the database first as you can see the member is not null and now we're going to serialize Our member into our Json string and set that value inside of redis so now that we have successfully cached Our member we're going to return from this method and successfully complete our API call as you can see we get the response inside of Postman and now we're going to send our request again this time the member is cached inside of redis so let's see how our method behaves this time we again hit the breakpoint inside of the cache member repository and we create our cache key and now we are calling the yet string method which is going to get us the value for the given key and if we execute this method you can see that the cached member value is not now if we take a look here you can see that we have the Json for our member object we're going to skip over the if statement here because our cache member does have a value and we're going to hit this line here where we are deserializing our cached member Json value into a member object instance if I execute this you can see this does complete successfully but if I take a closer look here I can see that something is not quite right the ID has the good empty value and also the email first name and last name value objects all don't have a value set why is this happening if I take a look at the Json again you can see that these values are indeed present here's the email the value is there the first name value is there the ID is also there but when we deserialize this into a member instance it is not properly set I'm going to stop the application and we're going to see how we can solve this problem if I go inside of the member class and we take a look at the properties here you can see that the properties that are problematic and are missing a value all have a private setter if you recall the created on and modified on properties did get a proper value when we were deserializing because their Setter is public but we have a problem with this free and the ID which all have a private Setter so how can we solve this and get our value properly deserialized from Json before I show you this solution if you're enjoying this video about caching with redis I'm going to need you to smash that like button and also subscribe to my channel so that you don't miss any of my future videos what we need to do here is we have to define a custom contract resolver for handling private properties I already created one and we're just going to review it so I'm going to go over to the private resolver class it inherits from the default contract resolver which is coming from mutants of Json and I'm overriding the create property method to properly configure the serialization logic for our private properties I'm first calling the base create property implementation to get the Json property back and if the property is not writable we are casting Our member argument into our property info object we're calling the get set method of this property which is going to return the setter if it exists and I'm also specifying true to tell the getset method that it should consider non-public setters if it turns out that this property does have a private setter this is going to be true and we set the writable property on the Json property instance and we just return it from this method to tell Newtons of Json that it should use our Custom Contract resolver we need to specify another argument here which is the contract resolver and I'm going to give it a new instance of our private resolver so let's run our application again this time using our Custom Contract resolver and see if the deserialization functions properly I'm going to send the get request from Postman again which is going to hit our breakpoint inside of the cached member Repository we hit our breakpoint so let's try to get the value from the cache this is because I did not shut down the redis instance it's still running in the background and it still contains the value for our cache key because the cache member Json is not empty we are going to go over this if statement and we're going to hit our deserialization again so let's execute it and see what we have this time if I take a look at the member instance you can see that the ID and the other value objects all have their properties correctly set and we can successfully return from this method and complete our API call as you can see I get a response back in Postman I removed the breakpoint from the cache member repository temporarily because I want to see what is the performance we're getting when we are using redis so I'm going to send this request to the API a couple of times and we're going to observe the response time so we're down to 19 milliseconds 17 10 12 and if I keep running it it's going to average around 10 11 12 milliseconds it looks like I can't remember exactly what the performance time was when we were using the memory cache but I think it was lower than what we have here which is expected because redis is running as a separate service to our API so there is the cost of the network hop to our redis instance the benefit is that we can reuse the same redis cache between multiple instances of our application which we could not do when we were using the memory cache implementation we're back in the cache member repository and I want to address one more thing that was not covered in the previous video where I was using the memory cache the problem here is that we're using any framework as our orm and what Entity framework does is it tracks the changes of all the entities it loads from the database inside of the change tracker in this case here when the member is returned directly from the database any framework tracking is going to work correctly but in this case here it's not going to work since we are deserializing the member from Json so if you want to change tracking to work even when the member is resolved from the cache we have to make a slight adjustment in this method I'm going to inject our application DB context here we need to initialize it from The Constructor and I'm going to go back to our get by ID method so right here after we deserialize the member from Json we need to tell Entity framework that it should track this member inside of the change tracker so I'm going to say DB context set member and I'm going to call the attach method and specify the member entity here and since the member can be null we only want to do that if the member is not now so I'm going to say if member is not known then we need to attach it to the DB context so this is how you can Implement caching using redis running inside of Docker and the distributed cache interface that is available inside of asp.net core make sure that you take a look at these two videos that you can see on the screen right now and until next time stay awesome
Info
Channel: Milan Jovanović
Views: 29,965
Rating: undefined out of 5
Keywords: asp.net core, asp.net core tutorial, asp.net core 6, asp.net core api, asp net, asp.net caching, asp.net core caching, asp.net core redis, asp.net redis, redis, caching, redis caching, redis cache, asp.net core redis caching, asp.net core redis cache, asp.net redis caching, asp.net redis cache, asp.net core distributedcache, asp.net core distributed cache, asp.net core memory cache, asp.net core memory cache vs distributed cache
Id: Tt5zIKVMMbs
Channel Id: undefined
Length: 18min 19sec (1099 seconds)
Published: Tue Nov 15 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.