Caching is something you see in everything. The page you are reading has cached parts too. It’s even the most used pattern in software development. However, there are different ways of creating and managing a cache, but this tutorial will focus on how to use in-memory caching with C# and .NET 7. I will explain the idea behind caching and show you the basic implementation of in-memory caching with C#.
Table Of Contents
What Is In-Memory Caching With C#?
Caching is a way of storing temporary data to make software applications quicker and greatly improve your application’s performance especially if you are using a lot of data.
Let’s imagine you have a database with a lot of movies. You want to retrieve those movies. You should write code that retrieves that data from the database and stores it in a variable. Okay, cool. Now, what happens if you want to retrieve those same movies again? Your code will retrieve those movies from the database again and store them in the same variable. It will also take two calls to the database. No problem, right?
But what happens if 1000 people do the same simultaneously? A thousand calls to the database happen, making your application slower since those people have to wait for the calls to finish. Additionally, if the database is across the world you might experience some lag.
To avoid this problem we can implement caching. With caching you would make the code call the database once, store it in a cache, and continue. The next time someone needs those movies, it will check if the cache already contains the movies and if so, it will return the cached version, and continue. If not, it will retrieve the data from the database.
With in-memory caching with C#, you improve the performance of your application.
What To Save In The Cache?
It depends on what you are doing. But the basic rule is:
If the data doesn’t change (a lot), cache it.
An example I usually give is a registration form. Most of the time you can select your country. Countries are a given and don’t change much. Maybe once a year or even once a decade. Depends on how some leaders behave. The names of the countries are usually stored in a database. Retrieving them from the database every time someone wants to register isn’t a smart idea. Thus, caching them would be better.
A list of users in a chat isn’t a good idea to cache. Users tend to enter and leave all the time. This data changes to quick to cache.
Caching Types
There are three types of caching:
- Persistent in-process Cache
The cache is stored in a file or database. The advantage is that if the process (application, web app, etc.) stops the cache keeps existing. - Distributed Cache
The cache is being saved on a physical server. A good example of this type is Redis/ This was built for Linux but works with .NET too. - In-Memory Cache
The cache stays in the process. If the process stops the cache will be deleted as well.
Eviction Policies
Alright, question: What happens if a movie is deleted or added to the database?
To avoid this, we (the developers) could make sure the cached version will be deleted as soon as data is changed and the cached version isn’t up to date anymore. We don’t have to do this because we can use Eviction policies (aka Removal policies). This is a set of rules that takes care of old cache.
There are a few policies:
- Absolute Expiration policy
This sets the duration of a cached item. It tells how long data can live in the cache. There is no exception. - Sliding Expiration policy
A cached item will be deleted if it’s not used anymore.
When the absolute expiration is 1 minute and the sliding expiration is 30 seconds, the item will be deleted as long as it’s not used within those 30 seconds. If the cached item is used every 20 seconds it will be deleted in 1 minute. - Size Limit policy
Size is important. If a cached item grows above the set size it will be deleted.
Complete Project For In-Memory Caching With C#
If you don’t want to read this whole article (although it took a lot of effort to write it), you can skip it all and just download the code on my GitHub:
https://github.com/KensLearningCurve/UsingCachingInCSharpAndDotNet6
Although it is written in .NET 6, you can easily use it in .NET 7 or 8. This repository has 3 branches: main, StartProject, and EndProject. Main is just main. StartProject contains the starting code that I will be using in this article. The EndProject contains the solution code, with the in-memory caching with C#, which I will explain in the article below.
Starting Code
Alright, let’s start!
If you want to follow this article by using the same code as I am, download the project from the GitHub repository, listed above. Make sure you are on the StartProject branch.
If you open the project you will see two projects:
CachingDemo.ConsoleApp:
This is a simple console application that writes the titles of a set of movies to the console. Nothing special here and I will hardly touch it.
CachingDemo.Business:
This is an important project. It contains a folder Entities. In this folder, you will find one class: Movie. It has a few properties, nothing special. This entity will be used in Entity Framework.
There is also a folder Migrations, which is connected with Entity Framework. The class DataContext is derived from DbContext. Here you should add or change the connection string. After that update your database with the update-database command.
The last class is MovieService. This class contains some methods to handle movies. It has a GetAll, Get(int id), Create, and delete. The DataContext is initialized in the constructor and used in each method to retrieve or send data from or to the database.
MovieService gets the DataContext injected. There is also an interface for MovieService. Since this is a console application, I added the ServiceCollection and ServiceProvider.
I kept the project small so you can get a better view of what we are changing. The console application makes two calls to movieService.GetAll(), which retrieves the movies from the database. Therefore, the movies will be retrieved from the database twice. And this is what we want to avoid.
Apply In-memory Caching With C#
To apply the in-memory caching with C# we should follow a few steps. First, we need to inject the interface IMemoryCache into the MovieService. Then we can use it and send or retrieve data to and from the in-memory caching with C#. Furthermore, we also need to tell the application we are using caching. And as last, we can set the eviction policies.
Inject IMemoryCache
The first thing we need to do before we can use the cache is inject IMemoryCache into the MovieService class. This interface is implemented on MemoryCache. This class handles everything with in-memory caching with C#. The constructor of the MovieService looks like this:
private readonly DataContext _dbContext; private readonly IMemoryCache memoryCache; public MovieService(DataContext dbContext, IMemoryCache memoryCache) { _dbContext = dbContext; this.memoryCache = memoryCache; }
Now we can use the memoryCache variable in the other methods. Let’s take a look at the new implementation of GetAll().
public IEnumerable<Movie> GetAll() { string key = "allmovies"; if (!memoryCache.TryGetValue(key, out List<Movie>? movies)) { movies = _dbContext.Set<Movie>().ToList(); memoryCache.Set(key, movies); } return movies ?? new List<Movie>(); }
Line 3 holds the cache key, which should be unique. On line 5 I check if the key exists in the caching. If so, then the variable movies is filled with the data from the cache.
If the key does not exist, I get the movies from the database on line 7 and save the result in the cache, which happens on line 8.
Last but not least, I return the movies variable on line 11, unless it’s null. Then I return an empty list.
An Error
That’s it! let’s try it out. Sadly, this results in an error:

This is because I didn’t tell the application to use caching. This is easy to fix. Just add the following code under line 8 in the Program.cs:
services.AddMemoryCache();
Caching Result
Let’s start the application again and… Behold! The result:
How can we check if it works with caching? Maybe add some logging. Back in the GetAll() method of the MovieService, let’s change the code:
public IEnumerable<Movie> GetAll() { string key = "allmovies"; Console.ForegroundColor = ConsoleColor.Red; if (!memoryCache.TryGetValue(key, out List<Movie>? movies)) { Console.WriteLine("Key is not in cache."); movies = _dbContext.Set<Movie>().ToList(); memoryCache.Set(key, movies); } else { Console.WriteLine("Already in cache."); } Console.ResetColor(); return movies ?? new List<Movie>(); }
On line 5 I change the console foreground color to distinguish the text from lines 9 and 15. On line 18 I reset the color again, which, in my case, should be white. This way we can see if it works.
Applying Eviction Policies
Let’s add some eviction policies. These can be set with the MemoryCacheEntryOptions. This is a builder where you can set the policies. I will be adding the sliding expiration and the absolute expiration.
public IEnumerable<Movie> GetAll() { string key = "allmovies"; Console.ForegroundColor = ConsoleColor.Red; if (!memoryCache.TryGetValue(key, out List<Movie>? movies)) { Console.WriteLine("Key is not in cache."); movies = _dbContext.Set<Movie>().ToList(); var cacheOptions = new MemoryCacheEntryOptions() .SetSlidingExpiration(TimeSpan.FromSeconds(10)) .SetAbsoluteExpiration(TimeSpan.FromSeconds(30)); memoryCache.Set(key, movies, cacheOptions); } else { Console.WriteLine("Already in cache."); } Console.ResetColor(); return movies ?? new List<Movie>(); }
I initialize the MemoryCachEntryOptions class first. Then the sliding expiration is set to 10 seconds. This means that the cached item will be deleted if it is not used within 10 seconds. Then I set the absolute expiration to 30 seconds. This mehat the cached item will be deleted if it’s older than 30 seconds and keeps being used within the 10-second cycle of the sliding expiration.
I added the initialized and set cacheOption as the third parameter of the set on line 16.
Changing The App
We are using a console application and an in-memory caching with C#. That means that as soon the application comes to an end, the cache is deleted because it lives in the memory of the application, not the machine.
So, how do we test if the eviction policies work? Let’s change the Program.cs a little. Paste the following lines of code on line 25 of the Program.cs:
Console.WriteLine("Press key"); Console.ReadLine();
When the first run is completed, the application stops until you press a key on your keyboard. If you start the application and hit the key within 10 seconds, the data will be retrieved from the cache. If you restart the application and wait 15 seconds, the data will be retrieved from the database and not the cache. This is because the sliding expiration is set to 10 seconds and after 15 seconds the cached item is deleted.
Different Life Cycles Of Caching
The cache of the console application is deleted as soon as the application stops. This is because the thread stops, which also holds the memory of the application. A console application isn’t the best example of using a cache. Mostly because a console application is used for small, quick usage.
A web application or an API would be a better example. If you configure the caching in the right way, each request could use the cache. This means that different clients, or visitors, can benefit from the cache. If you use the example in this tutorial in an API or web application, the cache will be created with each request. Not convenient.
It would be better to use caching with dependency injection, where you configure the dependency injection for the cache as a single scope. If you use this, the class of the caching won’t be initialized with each request but when the API or web application starts. Each request would use the same initialized cache class. How this works will be explained in a tutorial I will create shortly.
Conclusion On In-Memory Caching With C#
There you have it: Basic caching in C#. I kept this tutorial to a bare minimum with a lot of theoretical information. Just enough for you to use it, but maybe you miss some advanced topics.
There are also third-party packages you could use to create and manage the cache in your application. However, I find the way Microsoft made it easy to use and understand. The documentation is very good as well. Sure, you could write your cache mechanism, but keep in mind that it will take a lot of time to create something like this.
Related Articles