My favorite caching library is SO easy to configure a distributed cache alongside the in-memory cache. FusionCache makes it a cake walk!
In this video, we'll look at configuring FusionCache in an ASP NET Core app that's configured to use EF Core and Redis.
View Transcript
If you've been building ASP.NET Core applications and integrating caching, then there's no doubt in my mind that you've heard about Fusion Cache. Hi, my name is Nick Cantino and I'm a principal software engineering manager at Microsoft. This is another installation in this series where we're going to be talking through more caching, entity framework core, SQL, Reddus, all sorts of fun stuff. And this video is going to be focused on going over to Fusion Cache. So, if you haven't checked out the previous videos in the series, I'd recommend checking out the playlist up here. Otherwise, we can continue on looking at how we can switch our application over to using Fusion Cache. If that sounds interesting, just a reminder to subscribe to the channel and check out that pin comment for my courses on domain. Let's jump over to Visual Studio and check this out. Okay,
to kick things off, I do have this ASP.NET Core web application. It's the same one we've been using in all of the previous videos in this series. I have things left off with how we were using entity framework core in terms of the dependency injection and getting things set up. We are going to be looking at fusion cache. So the first thing that I want to do is jump over to the project file and we can see the different nougat packages that we have to go include. These are from Ziggy Creatures. This is Jod Denetti. I want to show you in just a moment here that if we go over to the Nougat package manager and click on one of the fusion cache entries. I wanted to make a note of this because I think that it's extremely underrated, but the documentation for fusion cache
is actually amazing and I got to talk to Jod in person about this. He really does take pride in the documentation, but you can see even on the right side of my screen, just when you're looking through the package manager, the documentation that comes up right away is already super helpful for being able to navigate things. But in just a second here, if I switch over to the actual GitHub, we can see the documentation in the left here. And this is one of the files that I pulled up just to be able to look through and make sure that I can get my caching set up with Reddus to be able to make this video properly. It's really awesome. There's tons of pictures. In my opinion, the language that's used in the documentation isn't super technical. It's not written like a lawyer or something wrote
it. It's really, in my opinion, quite straightforward. Lots of links to other parts of the documentation. And the other great thing is that he covers tons of different examples. I do highly recommend if you're going to be using fusion cache, jump over to the documentation, give it a read through and if you're finding things confusing, I'm sure that the maintainer would be happy to try and improve the documentation. But if we go look at just this part, we are going to be talking about Reddus with fusion cache today. And if you look through, there's tons of other packages that we could be using for other types of data stores for the distributed cache part that we're going to be looking at. We are going to be using Reddus like I said and if I can find it with my eyes it's right up at the
top actually. So this is the package we're going to be using but um it's really cool that there's support for lots of other things. Before we move on this is just a quick reminder that I do have a course on C refactoring available on domain. Refactoring is one of the most critical skills that you can learn as a software engineer and this helps you continue to build upon applications that already exist making sure that they can scale and have extensibility. I walk you through a bunch of various techniques and give you some examples that we walk through together to see how we can apply these techniques to refactor the code. Check out the pin comment and the links in the description to get this course. Now, back to the video. The other thing to mention because this was in the project file is that we
have to pick a serializer that we want to use for the distributed caching part. So, we are going to be using serialization system text JSON. You can use Newtonoft if you still like using that. And then there's protobuff and some other options as well. I'm going to jump back over to Visual Studio and again just to have another quick look at the project file. Let me jump over to that. It's just these ones that I have here. So, fusion cache the back plane is going to be stack exchange reddus and for serialization system text JSON. At the time of recording, it's just version 2.2.0 for me. By the time you're watching this, if there's something later and better, you may want to consider that. And keep in mind that if that's the case, there may be some API differences or some other ways to configure
things. So just a mental note for you. Let's jump back over to the program.cs file. And now let's think about how we have to go change things in order to support Fusion Cache. Number one is that we probably want to figure out how to wire this stuff up, right? So usually for the dependency injection, we had Entity Framework Chorus stuff being hooked up. That's this part here. And we had it with the hybrid cache from before. And then we had to go add the hybrid cache itself into the services. And then there was some configuration for Reddus. Now we can replace that code with this builder. Call to add fusion cache. And then we have to add the serializer. So let me go get the name space brought in and then specifically this other name space for system text JSON. This is giving us the
ability to be able to serialize our entities to and from the distributed cache with a particular serializer. in this case system text JSON. And then the next part is going to be us configuring Reddus. So if I go pull this back over a little bit, get this set up kind of like that. We have to just get the right name space included here. And there we go. So what I'm doing in this example is adding Reddus as a distributed cache to fusion cache. But then we're going to get the connection string from the app settings. So you can see that I'm just using configuration get connection string and then the name of the connection string is just Reddis connection string. If you're curious where that is, if I jump over to app settings in the left nav here, just under connection strings, like I said,
Reddus connection string and I just have it on the default port for Reddus. The next part, and this is optional, and there's tons of other options that you can do here, is that I'm just using with default entry options and setting an infinite duration. That's probably not something you want to do in your caching application. This is just for me to be able to demo this, but there are plenty of other options that you can go look through, right? And they're all well doumented. So, like I said, Jod Denetti has done an tremendous job with writing good readable, understandable, helpful documentation. I feel like I don't say this enough because I don't see examples of this ever. I'm the kind of developer where I'm like, I'm just going to get in Visual Studio, IntelliSense my way through things. But when I went to go use
Fusion Cache and I saw the documentation, I was like, "Oh man, I actually want to go reading this so I can understand more features." If you're building packages and stuff like that and you want good examples of writing good documentation for other developers, I highly recommend following in his footsteps. I'm not going to configure any other options here, but this is how we get Fusion Cache set up as a service through dependency injection. We're not quite done though because now that we have Fusion Cache set up, we still have to make sure that the repository that we're using with Entity Framework Core, which is another quick reminder here that I know tons of people hate the idea of a repository wrapping Entity Framework Core. It's just abstraction hell. Why are we doing this? It's too many levels of abstraction. This is just part of this
entire video series, so you can see me mixing and matching some of the pieces we're working with. But that's done on line N. And I'm going to jump into this extension method. And we can see from the previous videos, like I recommended at the start of this one, if you haven't watched them yet, please do if you want to see how this is all progressing. We have this code that existed before. Essentially, we were using a decorator pattern, which is going to allow us to wrap a repository with another repository that has caching. But the type of the cache that we were using was a hybrid cache. Fusion Cache does not implement the same interface as hybrid cache. Yes, there is a solution to this. And yes, I will have a follow-up video on this, but that's not for this video. So, instead, what we're
doing is making a new extension method. I just expanded it. It looks almost identical, right? Big difference is that the specific repository we're going to use is this Fusion cache repository. If you see where my cursor is highlighting fusion cache repository up here, it's the same spot, but it's hybrid caching repository. So just the specific implementation that we're working with for caching, that's the decorator repository. That one is going to be different. We are going to call this instead. I'm just going to go back to program.cs and we're going to change this one here. So, this part's all done, but I skipped over a part which I'll explain now because I had to go introduce Fusion Cache Repository. Before I walk through that, I just want to show you the hybrid caching one as a little bit of background if you haven't watched the other
videos. But if we look very quickly at all of these methods on here, they're essentially like a pass through method almost, except there's a caching call that happens in here as well. When we go to get something from the repository, we have it wrapped here, right? There's the repository get async, but we have it wrapped with a caching method. And if we we skip over get all async, I covered this in previous videos. Uh get all in terms of caching and stuff like that can become more complicated. Lots of different ways you can do that. But the create async, we were saying we're just going to blow away the cache entry and create something new in the repository. Same with updating and deleting is very much the same. So, we only cache things when we're reading them back through. That was by design from earlier
videos, but you can make your own design decisions. If we want to look at the Fusion cache repository now that you've seen a quick view of the other one, we can go see that we have the same structure, right? It takes in I fusion cache instead of a hybrid cache. It still takes in an I repository. all very much the same, but the method signatures are almost identical, just slight differences in the naming convention. We can see that we're using the repository and the cache here the exact same way. It's identical. It's just that on this method get or set async, the name was a little bit different and the name of the cancellation token is token. So because it's a name parameter terms of the other arguments that we can provide, I just had to go add the name explicitly in here. So this
would compile properly. We'll skip over get all async. And then I just wanted to quickly show you that based on what I was saying from the previous repository, we can decide if we want to remove or set on writing as well. Right? So if we comment this line out, the remove async is what we had in the other one. Right? We were saying if we're going to go write something into the database, then we can just take the opportunity to clear the cache. On create, we probably really don't have to worry about this. Something shouldn't exist there with the same ID. I would really hope. But that same pattern for create an update can be used. Or if we wanted, we could say, let's not remove, let's actually update the cache when we go write this thing in here. If you know that based on
how your system is designed that when you go write something into the database that odds are you're probably going to want to read it back very soon, then it might be a really good idea that when you're writing, you also go update the cache. But you have this as an option. I'm not telling you how to go design it. You can do whatever you would like, but I just wanted to show you the variations. When we go to delete something, we probably just want to remove it from the cache. I think that makes the most sense. But overall the structure of this is almost identical. It's just that the method signatures were slightly different in terms of their names and the type i fusion cache had to be used instead of hybrid cache. Like I said, I will make a follow-up video where we can
actually use fusion cache instead of hybrid cache or in terms of the implementation, we can swap it out and that way we can actually keep the signature the exact same. Okay, at this point we have everything we need to get up and running. We have our dependency injection set up with our repository and the decorator that is going to be using Fusion Cache. We also have Fusion Cache set up with Reddus and some default behavior for our options. At this point, I'm going to go ahead and run this. We can go walking through how we can pull records back out and see that we're hitting the cache. All right, I've started the console application. The other thing that we need to do is go over to Docker and we have our container running. I'm just going to go ahead and delete this one and we're
going to create a new one. I'm going to go back to images. I'm just going to run a new Reddus instance. I have a video on this if you're interested. It's included in the playlist. This way you can see how you can get a local Reddus instance up and running if you're interested in that. Just so you can follow along. Go ahead and press run. And we can see that right away we have a Reddus instance up and running. So that's great. Now we should be able to go hit our web API with an ID and get a value back. Okay, I have my browser open from before where there was an entry already. The value should include dev leader. So let me go ahead and press enter. We can see that fusion cache is doing some logging here. It's very verbose by the way.
You can turn that off and adjust the logging level. It's helpful for debugging, but beyond that, I would say far too noisy for production. But we didn't get a cache hit. We got the record back. But you can see if we look in the left here, this is coming from Entity Framework Core. We can see that it's going and running a SQL query. It's like it's not in the cache. I got to go get this thing. But that means it should be cached at this point. So if I press enter again, we can see that fusion cache runs. There is no more printing of this text up here. It's not going to the database anymore. So, if I press enter one more time and again and again, there's no more going to the database because things are in the cache. At this point though, you
might be saying, Nick, that's cool and all, but what does Reddus have to do with any of this? You could have just done this with a memory cache. And you're totally right. And it might be misleading if you were thinking that all of this was just because of Reddus. It's not necessarily. This is just how we get caching support with everything we wired up. So, let's see what happens if we want to go run this again. And we have Reddus still up and running. Because if you recall when I first started this, let me get this spread out so you can see more easily. We saw at the beginning, we had to go to the database in order to get this record. And that's because it was not loaded up into the cache yet. So, if I kill this off. Okay. So, now Reddus is
still running in the Docker instance. So, I'm going to go start this back up. If the record was only stored in the memory cache, then we will see that it goes back to SQL to pull it back in. However, if it's all working with Reddus, we should be able to get it from the distributed cache because that should be much faster than going to the database. So, let's go run this. Okay, so there there's ASP.NET Core up and running. I'm going to go ahead and try to access this record. And remember, we're looking for in the console, do we see any SQL? And like I said, it's a little bit noisy, but there are no lines from Entity Framework Core saying that it's doing a SQL query. And we got the result back, right? We get the record that has dev leader in it. That's
proof for us that it was actually leveraging Reddus. It's not that it was stored in memory. I killed the application. That's not preserved in memory anymore. The new instance when we asked for this record was able to go get it from Reddus and now it will be in the memory cache as well. So, if I keep doing this, you will see that nope, it's not logging anything that says SQL. I realize it's really hard to go read through all of this if you're not familiar with what's being output, but there are no SQL logging lines that are showing up in the console. Okay, one more quick thing to touch on is that I'm going to go back over to Docker Desktop and I'm just going to kill off our Reddus instance. Deletion failed. Okay, that's not what I wanted. I wanted the container. Let's go
ahead and delete that. Bye-bye. Now what happens right we have this up and running it's using Reddus except it's gone now. So if I go to ask for the record you can see still working totally fine because it's in the memory cache. It doesn't have to go to Reddus because it's in memory. Awesome. But that means that things are probably broken if we don't have Reddus up and running and we kill this off now. So let's go ahead and stop it. And what we should see because Reddus is not running is that when we start this back up, it's unable to get the cache populated, right? There's no Reddus that has that secondary L2 cache for us. So, we go run this. And when we go to fetch that data, we'll see that it does have to go to the database. Again, let's go ask
for that record. Pay attention to the spinner still going. This is behavior because Reddus, we're trying to connect to it right now. That's what fusion cache is trying to do. These types of things are all configurable on Reddus for how long it's going to wait. So, not a good uh sort of uh experience if you're trying to reduce latency, right? We weren't able to connect to Reddus. You can see there's exceptions in here, right? Reddis connection exception. It timed out. So, like I said, you can configure all of that, but we were still able to get the record, right? We fetched it. We get dev leader in the browser. If I press enter again, it's going to try doing it again going forward. if it's able to, it's not going to keep contacting Reddus on every single attempt because it does have it in the
memory cache. Now, so something to keep in mind is that your applications still can survive if the distributed cache goes down. It's just that your back plane for fusion cache is not going to be working properly because it's down. So, you can still survive with your L1 cache, but your L2 cache is down. So, that's the end of this particular video. We got to see how we can set up Reddis with fusion cache with entity framework core with a repository design pattern with a decorator design pattern and hook all of these things up. We were able to switch it all out without having to touch any other part of our application. We just changed the configuration at startup. This is one of the meta points that I'm trying to get people to see as we go through all of these videos is that yes, the
technology is super cool. I love Fusion Cache. which I think it's awesome and we can see that by leveraging some of the design patterns, we get this flexibility where we can swap out the implementations and not have to worry about changing any other part of our app. If you thought that was interesting, then this next video we're going to look at is doing the same thing with Dapper. Check it out next.