ASP.NET Core Basics: Exploring Cache In-Memory (2025)

Using in-memory caching improves the performance and scalability of web applications. In this blog post, we will check out how to implement in-memory caching and see the benefits it offers in practice.

The use of cache is essential in scenarios where a large amount of data is read, as it makes this data accessible and less expensive compared to traditional methods such as direct access to the database for each request.

ASP.NET Core has excellent mechanisms for dealing with caching. In this post, we will explore in detail what in-memory caching is, how it can be configured and used in ASP.NET Core, and the best practices for managing the cache effectively.

What Is Caching?

In computing, caching is a technique that temporarily stores data in an easily accessible location, which may be in memory or another source.

The main advantage of using a cache is to avoid accessing the standard storage device, such as a database, which can often be costly. Thus, the data is stored in a temporary source that is easier to access, making querying this data faster and cheaper.

ASP.NET Core Basics: Exploring Cache In-Memory (1)

What Is Cache In-Memory?

ASP.NET Core supports several different types of caches. The memory cache is the simplest and is stored in the web server’s memory. The in-memory cache can store any kind of object in key-value pair format.

It’s possible to implement in-memory caching using two approaches:

  1. Using the System.Runtime.Caching/MemoryCache namespace is part of the .NET Framework and provides an API for in-memory caching. It’s a solid option, especially for dealing with legacy code.
  2. Using the Microsoft.Extensions.Caching.Memory namespace is the best approach for new ASP.NET Core applications. It is part of the ASP.NET Core features and provides a more modern and flexible implementation of in-memory caching.

The in-memory cache in ASP.NET Core temporarily stores data in the server’s memory, allowing it to be retrieved quickly without redo operations, which in many cases can be costly.

When data is accessed for the first time, it is normally fetched from slower sources, such as a database or an external service, and then a copy of that data is stored in cache memory. If the same data is requested again, the system checks whether it is in the cache. If so, the data is delivered quickly from the cache, thus avoiding searching the sources.

Finally, it is possible to use cache expiration or invalidation policies that act periodically to update or remove data from the cache, for data consistency and allowing only the most relevant data to take up space.

Implementing In-Memory Caching

In this post, we will create a simple API to manage temperature data. We will use SQL Server to record and retrieve this data, and then we will check the performance of queries using the in-memory cache.

You can access the complete code here: Weather Forecast API Source code.

Prerequisites

You must have the latest version of .NET. This post uses Version 8.0.

You also need a pre-configured local SQL Server connection. You may use any other database, but this post’s example uses SQL Server together with the Entity Framework Core.

Creating the Application and Installing the Dependencies

To create the sample application, you can use the following command:

dotnet new web -n WeatherForecastAPI

To install the NuGet packages you can use the commands below:

dotnet add package Microsoft.Extensions.Caching.Memorydotnet add package Microsoft.EntityFrameworkCore.InMemorydotnet add package Microsoft.EntityFrameworkCore.SqlServerdotnet add package Microsoft.EntityFrameworkCore.Toolsdotnet add package Bogus

Creating the Entity

Open the project with your favorite IDE. Create a new folder called “Models” and inside it create the following class:

namespace WeatherForecastAPI.Models;public class WeatherForecast{ public int Id { get; set; } public string City { get; set; } public double TemperatureC { get; set; } public string Summary { get; set; } public DateTime Date { get; set; }}

Creating the Context Class

This example uses EF Core, so we need to create a class to extend the DbContext class. For that, create a new folder called “Data” and inside it create the class below:

using Bogus;using Microsoft.EntityFrameworkCore;using WeatherForecastAPI.Models;namespace WeatherForecastAPI.Data;public class WeatherForecastDbContext : DbContext{ public WeatherForecastDbContext(DbContextOptions<WeatherForecastDbContext> options) : base(options) { } public DbSet<WeatherForecast> WeatherForecasts { get; set; } public void SeedDatabase(int numberOfRecords) { if (WeatherForecasts.Any()) return; var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; var faker = new Faker<WeatherForecast>() .RuleFor(w => w.City, f => f.Address.City()) .RuleFor(w => w.TemperatureC, f => f.Random.Double(-20, 55)) .RuleFor(w => w.Summary, f => f.PickRandom(summaries)) .RuleFor(w => w.Date, f => f.Date.Past(0)); var weatherData = faker.Generate(numberOfRecords); WeatherForecasts.AddRange(weatherData); SaveChanges(); }}

Note that here we defined a database context called WeatherForecastDbContext, where the method SeedDatabase(int numberOfRecords) is declared to fill the database with dummy data using the Bogus library.

First, the method checks whether there are already records in the weather forecast table. If they exist, the method returns without doing anything, preventing data duplication.

The method then defines an array of weather forecast summaries, such as Freezing, Hot and Mild. Next, the Faker<WeatherForecast> class instance is configured to generate WeatherForecast objects with random values for the city, temperature, summary and date properties. The temperature is generated within a specific range (-20 to 55 degrees Celsius), and the date is a random one in the past.

This data will be used to verify the functioning of the in-memory cache later on.

Creating the Database Configurations and the API Endpoints

The next step is to declare the connection string settings and the endpoint that will implement the use of data in the in-memory cache.

Replace the Program class code with the code below:

using Microsoft.EntityFrameworkCore;using Microsoft.Extensions.Caching.Memory;using WeatherForecastAPI.Data;using WeatherForecastAPI.Models;var builder = WebApplication.CreateBuilder(args);string connectionString = builder.Configuration.GetConnectionString("DefaultConnection");builder.Services.AddDbContext<WeatherForecastDbContext>(options => options.UseSqlServer(connectionString));builder.Services.AddMemoryCache();var app = builder.Build();app.MapGet("/weather/{city}", async (string city, WeatherForecastDbContext db, IMemoryCache cache) =>{ WeatherForecast? weather = null; if (!cache.TryGetValue(city, out weather)) { weather = await db.WeatherForecasts .OrderByDescending(w => w.Date) .FirstOrDefaultAsync(w => w.City == city); if (weather != null) { var cacheEntryOptions = new MemoryCacheEntryOptions() .SetAbsoluteExpiration(TimeSpan.FromMinutes(10)); cache.Set(city, weather, cacheEntryOptions); } } return weather == null ? Results.NotFound("Weather data not found for the specified city.") : Results.Ok(weather);});using (var scope = app.Services.CreateScope()){ var db = scope.ServiceProvider.GetRequiredService<WeatherForecastDbContext>(); db.Database.Migrate(); db.SeedDatabase(10000);}app.Run();

Here we defined a configuration to obtain the connection string with the database GetConnectionString("DefaultConnection").

We also added the database context service (WeatherForecastDbContext) to the dependency injection container, configured to use SQL Server with the provided connection string.

Then we added the memory cache service with the configuration: builder.Services.AddMemoryCache().

An API route /weather/{city} is also defined using app.MapGet. This route accepts the name of a city as a parameter and uses the injected database and memory cache services.

Inside the route, the code tries to get the weather forecast from the memory cache. If the prediction is not in the cache, it queries the database.

The most recent forecast for the specified city is obtained from the database by ordering the forecasts by date in descending order and taking the first record that matches the city. If the prediction is found in the database, it is added to the cache with a 10-minute expiration. The method returns the weather forecast if found, or a NotFound response.

The db.Database.Migrate() method applies any pending migrations to make sure the database is up to date, and the db.SeedDatabase(10000) method populates the database with 10,000 dummy weather forecast records if empty.

Note how simple it is to configure the search for data in the cache and insert it if it does not exist.

Generating the Database Migrations

Before running the application and testing the cache search, we need to add the connection string to the project and run the EF Core migrations to generate the database schemas.

So, inside the file appsettings.json add the code below:

"ConnectionStrings": { "DefaultConnection": "Server=YOUR_LOCAL_CONNECTION;Database=WeatherForecastDb;Trusted_Connection=True;MultipleActiveResultSets=true" },

Replace the text YOUR_LOCAL_CONNECTION with your local data configuration.

Now, open a terminal at the root of the application and run the EF Core migration commands. Remember that you need to have EF Core installed globally. If you don’t already have it you can use the following command:

dotnet tool install --global dotnet-ef

EF Core migration commands:

  • Create the initial migration
dotnet ef migrations add InitialCreate
  • Update the database
dotnet ef database update

Testing In-Memory Cache Efficiency with Fiddler

Now that we have created and configured the application, we can run it and check the efficiency brought by using the cache. So, just run the application and, through Telerik Fiddler Everywhere, make a request to the route /weather/{city} using one of the cities entered in the database as a parameter. Note that the database will be populated when running the application.

The images below demonstrate requests to the API using Fiddler. When inspecting the details in the Traffic tab, we can see the first request took 332 milliseconds. This is because, in the first request, the data was not in the cache; so the API fetched the data directly from the database, and then added it to the cache.

The second request took just 15 milliseconds, as the API fetched the data from the cache, considerably shortening the time needed to return the data.

ASP.NET Core Basics: Exploring Cache In-Memory (2)

ASP.NET Core Basics: Exploring Cache In-Memory (3)

ASP.NET Core Basics: Exploring Cache In-Memory (4)

To calculate how much more efficient the second request (using the cache) is compared to the first, we can use the following formula for relative efficiency:

Relative Efficiency = First Request Time / Second Request Time

Relative Efficiency = 332 ms / 15 ms

Relative Efficiency = 22.13

This means the second request was approximately 22.13 times more efficient than the first. In the example in the post, a small amount of data was used; however, there are scenarios with significant amounts of data where the cache proves to be extremely efficient in making requests less costly.

Other Options for Handling In-Memory Caching

In addition to the example above, other possibilities exist for dealing with memory cache, such as inserting, updating and removing the cache.

1. Adding Cities with Weather Forecasts to the Cache

The endpoint below lists the different cities and checks if they are in the cache; if not, they are inserted, configuring an expiration time of 30 minutes. Adding items to the cache in advance is useful because it improves application performance by reducing the number of repetitive database queries. This speeds up response time, saves database resources and provides a more efficient user experience.

app.MapGet("/weather/cities", async (WeatherForecastDbContext db, IMemoryCache cache) =>{ const string cacheKey = "cities_with_weather"; if (!cache.TryGetValue(cacheKey, out List<string> cities)) { cities = await db.WeatherForecasts .Select(w => w.City) .Distinct() .ToListAsync(); var cacheEntryOptions = new MemoryCacheEntryOptions() .SetAbsoluteExpiration(TimeSpan.FromMinutes(30)); cache.Set(cacheKey, cities, cacheEntryOptions); } return Results.Ok(cities);});

2. Update Cache Manually

It is possible to update the cache manually. Suppose you were notified that a city’s data was updated in the database. You can use the endpoint below to update the data in the cache.

app.MapPost("/weather/cache-update/{city}", async (string city, WeatherForecastDbContext db, IMemoryCache cache) =>{ var weather = await db.WeatherForecasts .OrderByDescending(w => w.Date) .FirstOrDefaultAsync(w => w.City == city); if (weather != null) { var cacheEntryOptions = new MemoryCacheEntryOptions() .SetAbsoluteExpiration(TimeSpan.FromMinutes(10)); cache.Set(city, weather, cacheEntryOptions); return Results.Ok($"Cache for city {city} updated."); } else return Results.NotFound("Weather data not found for the specified city.");});

3. Remove a Specific Item from the Cache

If for some reason you need to remove a specific item from the cache, you could have an endpoint like this:

app.MapDelete("/weather/cache-delete/{city}", (string city, IMemoryCache cache) =>{ cache.Remove(city); return Results.Ok($"Cache for city {city} removed.");});

4. Clear All Cache

It is also possible to clear the entire contents of the cache. To do this, simply use the Clear() method of the MemoryCache class.

app.MapDelete("/cache/clear", (IMemoryCache cache) =>{ if (cache is MemoryCache concreteMemoryCache) concreteMemoryCache.Clear(); return Results.Ok("Cache cleared.");});

Conclusion and Final Considerations

In scenarios where there is a large amount of data and this data must be accessed quickly, adding a caching mechanism can be crucial for the functioning of the application and a good user experience. Furthermore, using the cache prevents excessive access to the source of data, such as a database, resulting in resource savings.

In this post, we saw how to implement in-memory caching in an ASP.NET Core API and how efficient requests are compared to requests without using the cache. Furthermore, we saw how to manipulate the cache by adding, updating and deleting data from the in-memory cache.

When dealing with performance problems, try using the in-memory cache. It may be a simpler and more efficient option for your situation.

ASP.NET Core Basics: Exploring Cache In-Memory (2025)

FAQs

How to use cache memory in ASP.NET Core? ›

Here's how it works:
  1. Check the cache: Look for the requested data in the cache.
  2. Fetch from source (if cache miss): If the data isn't in the cache, fetch it from the source.
  3. Update the cache: Store the fetched data in the cache for subsequent requests.
Jun 8, 2024

How to clear cache in .NET Core? ›

By using the clearReportCache and destroy method, you can clear the server side cache. You have to use this method when closing report viewer and switching to another report within your application.

What is the difference between in memory cache and response cache? ›

Response Caching middleware adds required headers to the response. In-memory caching helps you to store the data that changes infrequently and is used during request processing.

How to cache API response in ASP.NET Core? ›

Response Caching Middleware is implicitly available for ASP.NET Core apps via the shared framework. UseCors must be called before UseResponseCaching when using CORS middleware. The sample app adds headers to control caching on subsequent requests: Cache-Control: Caches cacheable responses for up to 10 seconds.

What are the three main types of caching used in net? ›

ASP.NET has the following main types of caching:
  • Page caching.
  • Fragment caching.
  • Data caching.
Jan 31, 2023

How to improve cache memory? ›

Cache memory is built into the CPU or located very close to it, so it cannot be upgraded separately like RAM. To get more or faster cache, you would need to upgrade the entire CPU.

When should I use memory cache? ›

It is typically used when the following conditions are met: Repeatable Queries: If your application constantly makes the same queries for data, it's more efficient to cache this data in memory rather than repeatedly reading from disk.

Is cache faster than memory? ›

Cache memory is approximately 10 to 100 times faster than RAM, requiring only a few nanoseconds to respond to a CPU request. The actual hardware used for cache memory is a high-speed Static Random Access Memory (SRAM) whereas the hardware that is used in a computer's main memory is Dynamic Random Access Memory (DRAM).

What's the difference between middleware and a filter in ASP.NET Core? ›

Middleware operate on the level of ASP.NET Core and can act on every single request that comes in to the application. MVC filters on the other hand only run for requests that come to MVC. So for example, if I wanted to enforce that all requests must be done over HTTPS, I would have to use a middleware for that.

How to implement redis cache in ASP.NET Core Web API? ›

Implementation of REDIS Cache Using . NET Core API
  1. Install the following “NuGet Packages,” which need step by step in our application: ...
  2. Create the “Model” folder and create one product class inside that with the following details: ...
  3. Next, create the DbContextClass class for database-related operations as I show below:
Feb 26, 2023

What is client side caching in .NET Core? ›

What is Client-Side Caching? Client-side web caching refers to storing web resources, such as images and scripts, on the client side (i.e., the user's browser) so that they can be quickly retrieved without needing to be reloaded from the server.

How to use cache memory in C#? ›

How to Add MemoryCache to an ASP.NET Core App?
  1. ICacheEntry CreateEntry(object key) - adds an entry into the cache for the given cache key. If the entry already exists, it's overwritten.
  2. bool TryGetValue(object key, out object? ...
  3. void Remove(object key) - removes an entry for the given key.
Jul 1, 2024

How do I run cache memory? ›

How Does Memory Caching Work? Memory caching works by first setting aside a portion of RAM to be used as the cache. As an application tries to read data, typically from a data storage system like a database, it checks to see if the desired record already exists in the cache.

How to use output cache in .NET Core? ›

Add the output caching middleware to the service collection by calling AddOutputCache. Add the middleware to the request processing pipeline by calling UseOutputCache. In apps that use CORS middleware, UseOutputCache must be called after UseCors.

How to use redis cache in .NET Core? ›

Distributed Redis Cache
  1. Create an Azure Cache for Redis.
  2. Copy the Primary connection string (StackExchange. Redis) to Configuration. Local development: Save the connection string with Secret Manager. Azure: Save the connection string in the App Service Configuration or another secure store.
Jan 29, 2024

References

Top Articles
Latest Posts
Recommended Articles
Article information

Author: Horacio Brakus JD

Last Updated:

Views: 5327

Rating: 4 / 5 (51 voted)

Reviews: 82% of readers found this page helpful

Author information

Name: Horacio Brakus JD

Birthday: 1999-08-21

Address: Apt. 524 43384 Minnie Prairie, South Edda, MA 62804

Phone: +5931039998219

Job: Sales Strategist

Hobby: Sculling, Kitesurfing, Orienteering, Painting, Computer programming, Creative writing, Scuba diving

Introduction: My name is Horacio Brakus JD, I am a lively, splendid, jolly, vivacious, vast, cheerful, agreeable person who loves writing and wants to share my knowledge and understanding with you.