In earlier videos in the series, we looked at using IMemoryCache with Entity Framework Core. But there's a new kid on the block...
HybridCache!
Let's see how we can easily swap out our caching library for HybridCache.
View Transcript
Hi, my name is Nick Cosantino and I'm a principal software engineering manager at Microsoft. Today we're going to talk about caching. And if you've watched the previous videos in this playlist that I've been putting together, then you know that we've been working with Entity Framework Core, we've been working with Dapper and we've been able to see some in-memory caching. In this video that we're going to branch over to the hybrid cache innet. Now, I am going to make more videos in this series specifically with hybrid caching and some of the different features. So, this one's just going to be an introduction. We're going to be going from the previous code that we have with the memory cache in Entity Framework Core and then we're going to move over to the hybrid cache. So, if you have not watched the previous videos in this series, I
will put the playlist right up here. You can go check that out and then we're going to build from where we left off and switch over to hybrid cache. In follow-up videos, we'll look at setting up Reddus and leveraging hybrid cache with Reddus. Okay, so to kick things off, I'm going to jump over to the project. And we'll see that we have this package reference right here for Microsoft Extensions Caching Hybrid. And this is going to be using 9.4 at the time of recording. By the time you watch this, we might be on other versions. So don't sweat it. Hopefully, they've kept backwards compatibility. And this material is still relevant in terms of the APIs that we have access to. That's the package you're going to want to add. And again, if you've watched the previous videos, then you'll understand where all these other packages
are coming from and why we're using them. You will not need Dapper if you're following along with this video because we're going to be using ND Framework Core. But the other repositories that we've been putting together, we can mix and match them. So, you can kind of do whatever you'd like at this point cuz we're going to be focused on the hybrid caching aspect. We'll close out the project. We'll jump back to the program.cs file. This is where our application is essentially running from. What I want to talk about is how we're going to switch the code that we had from before over to using the hybrid cache. Just a quick recap, we had some get methods that are all mapping to uh create, read, update, and delete. Not good practice, but we'll be able to execute these from the browser, and we can see
some of this stuff taking effect nice and easy. But the other stuff that's really important is right up here where we're setting up the hybrid caching and entity framework core. So if you're not familiar with dependency injection, there's plenty of tutorials online to introduce you. I have plenty on my channel as well using the built-in stuff autofaccor. There's lots of options, but we're going to follow along with this sort of extension method syntax. And this is what we had before. So we had set up entity framework CRUD with the memory cache. So setup with the well I just had cache before right. So this is the method we had before. What I've done is I've added a new one and this is going to be specifically with hybrid cache. And then what we had to do is we had to specifically add in the memory
cache service but instead we don't use that and we're going to be adding in the hybrid cache. Let's go over to these extension methods and this way I can go compare what we had before and what we're going to use now. So this is the older method and this is where we had ND framework core and the first line that we see in this is another extension method. I've just pulled it down to here. Nothing too fancy. It's nothing specific with the caching that we're using. This is truly just to set up entity framework core with SQLite. So let me collapse that cuz that's not really the important part here. The important part is that we were using a decorator pattern in the previous videos. The idea behind this is that we're able to take an existing repository and then we can wrap that in
another one. Again, I have to have this disclaimer in every video that I talk about entity framework core and a repository pattern because everyone loses their mind and they say, "Don't do it. It's overkill. It's over abstraction." I get it. I'm not telling you to do that. I'm just showing you that we have these patterns and tools that we can work with. And I'm simply building up this series using a repository pattern. And this way we can flip between ND framework core Dapper and then we can do caching with this type of decorator pattern around it. So there's a method to the madness. I am using a repository pattern to leverage this stuff. But let's have a quick look. We can see that we're adding a singleton here that is the entity framework core repository. And then down here we have this caching repository. So
again, if you watch the earlier videos in this playlist, this is where we're using a decorator pattern to essentially decorate or wrap around the normal repository with a caching one. But because we don't want to just use the caching repository, we want to use the hybrid cache one. Now, you might be saying, "Well, Nick, why did we need a whole other repository?" So, let me just expand this. You'll see it looks almost the exact same. I'll put them both up at the same time, right? hybrid caching repository versus caching. But the shape of these is almost identical, right? Like if you weren't reading closely, they almost look the same. The keyword though is hybrid, right? If I just highlight this part, you can see the text is highlighted in both blocks of code. The memory cache here and hybrid cache here are different. We're using
dependency injection to pull in those specific services. But this is essentially where the issue is is that the memory cache and hybrid cache do not have the same interface here. The previous repository that we built, the one that can decorate or wrap around another repository was using the i memory cache interface. That's this one up here. If we go have a look at hybrid cache, if I F12 on that and we go to the definition of it, you'll notice this is using an abstract class and then there's no interface on here because hybrid cache and immemory cache don't have a compatible interface at this level. The previous repository we built uses immemory cache. I just can't put a hybrid cache directly into that. We could probably do yet another wrapper class around the hybrid cache. Something way over the top. That's just going to be
overkill. So, all that I did, let me go open up the caching repository. Again, this is covered in great detail in the previous video. So, I'm trying to go through quickly. If you're feeling like, hey, what's going on here? We're jumping around a lot. That's why I'm putting this playlist together and spending more time on each individual video to kind of walk you through it. But you'll notice this caching repository. It takes in a repository and a memory cache. It's wrapping this other repository and then using the memory cache as the caching mechanism. But like I said, the hybrid cache one does not have a compatible interface. So if I go open up the hybrid caching one, it's going to look almost the exact same. So let me put these beside each other. Right? If I click through them, they're going to look almost the
same. In fact, I will just put them side by side and this way we can try to look at them at the same time. You'll notice that the shape of them sometimes what I like to do and I mean this literally is blur my eyes a little bit and look at code and if I can see a common shape sometimes that tells me something about what the code is doing. But you'll notice that you know the constructors both take an repository and a cache, right? They're just a different type of cache. Let me scroll the get methods into view right at the top right. I got to go I think that's right um approximately. So this one's collapsed. There we go. But you'll notice the shape of these again is very similar, right? So we have a get or create. We have a get or
create. But you'll notice that this part looks a little bit different. And that's just because I must have missed a cancellation token. Right? I put get ID there. I don't have a cancellation token here. And that's because this one doesn't seem to take it. So um it's just like these subtle little details between the two. But the reality is like the code is almost the same, right? So get all a sync. If I put that up at the top, that's this one here. Um, but it's almost identical, right? If I scroll the delete one, we have the removal. It's not a sync on the right. The delete is a sync. So these things are very similar. The point is the code looks almost the exact same. It's just that the reality is the interface is not on the hybrid cache. There is no common interface.
So, let me go put that back over here. So, I'm explaining this just because when we go to look at the extension methods, what would have been really nice, especially with our decorator pattern and existing repositories, is if I didn't have to change them at all. If all that I had to do was say, don't use the memory one. Let me just register a hybrid one, and that's going to take effect automatically. That would have been like really, really nice. That would have been like chef's kiss. But that's not what we have unfortunately. So I had to duplicate this like I've already walked through and then I put hybrid cache here instead of memory cache and then again this specific caching repository instead of this normal one. So this is the hybrid one and this is the memory one from before. So with that out
of the way, lots of the boring stuff up front, but I have to explain how we're configuring this stuff, right? So now I can call this one with hybrid cache decorator. That's going to be the one we just looked at. I don't need to add a memory cache specifically anymore. You could, but we don't need to because by default, a hybrid cache will come with the memory cache. So, this part's new, the add hybrid cache. And we can do that because of that Nougat package that we looked at right at the beginning of this video. So, let me go ahead and expand that. There's a bunch of different options that you can configure. These ones aren't even required. So, technically, you could just leave them out completely. You don't need any options for that matter, right? So, you could essentially remove all of this and
just add your hybrid cache and you're set. You have hybrid caching. We've already hooked up the uh the decorator to go around the entity framework core repository. This will just work. But what I wanted to show, especially when we look at the future videos, is that we have an expiration and a local cache expiration. So, a bit of a spoiler alert. the code that's on line 16 that's commented out that adds reddus. When we go to look at that video, which I'll create after this one, we'll be able to see that we have different expiration patterns. So, I'm including a little spoiler here because if that sounds super cool, make sure you watch the next video when it's released. It will be added to this playlist. Okay, so what we're going to do from here is run this thing. It's not going to be very
exciting if you've watched the whole playlist up to this point because this is just going to be an in-memory cache. If this stuff is still kind of new to you, this will be good kind of proof that this is working as we expect. So, let's go ahead and run this. A friendly reminder that I am using SQLite as the backing store for this. There are some records that are already there and we'll see that in just a moment. Maybe let's make it look like that. And then I'm going to flashbang warning pull up uh SQLite expert. I know that's very bright. I'm so sorry about that. I wish there was a dark mode. Maybe there even is and I just haven't looked for it yet. But you can see that I have some records in here. Right. So this one here, if I pull this
up, we'll get an ID for one that already exists. And then I'm going to go back over to the browser. And you will see that I have this pulled up. And if I go to access this one, which is not the one that I have on my clipboard, right, we press enter. You can see that we had some execution, right? In the console window, we can see that we were going to the database. So if I press enter again, right, it's still going to the database. Maybe let's zoom out a little bit. So if I keep doing it, right, if I keep pressing enter, eventually it will time out in the cache, but I'm still doing it now. And notice how it's not adding new lines. And then it does. There's some evidence that we're caching even when we have a record that doesn't exist.
If I go look at this one now, because this one is not in the cache at all. If I go press enter, we should see that we have a SQL entry get pulled up. Boom. So that's what happened right over here. And then we have a record that's been found. And the same thing, right, for a record that is found. If I go press enter, right, it's not adding new console logging. But if I wait long enough and then press enter, boom, there we go. It flickers in the console because it's going back to the database. I'm not going to go through all the CRUD methods because I'm feeling for the people that have watched the previous videos. They're like, Nick, I've seen you go do create, update, delete so many times in this stupid console window. So, uh, don't worry. We're not going to
keep looking at all the console output. I'm not going to make you look at the browser as I go to change these parameters, but trust me, that's what's happening there. This one, like I said, is not super exciting in terms of what we're seeing happen between the browser and the console window. That's because we're using a hybrid cache, but it's only backed by a memory cache. Let me stop this. Let me go back to Visual Studio here. And I just want to remind you that hybrid cache is going to be able to include a memory cache and a distributed cache. It will be able to support both at the same time. So you can have like an L1 and L2 cache. And like I was hinting at, we have different expirations or different settings that we can have here. The way that this one is
configured right now, even though it says hybrid cache, because there is no configuration for Reddus or another distributed store, we are just using the default memory cache backing for the hybrid one. That's why this one wasn't super exciting, but we at least got to see how we can change our decorator because those interfaces don't match, but we can still use that common approach, which is really nice, I think. And then we'll see in the next videos that we can go add Reddus. And then we'll also look at being able to run Reddus locally with a Docker setup. So if all of that sounds interesting, stay tuned. You can check that out here when it's posted. Thanks and I'll see you next time.