Tutorial: Implement caching with .NET Aspire integrations
Cloud-native apps often require various types of scalable caching solutions to improve performance. .NET Aspire integrations simplify the process of connecting to popular caching services such as Redis. In this article, you'll learn how to:
- Create a basic ASP.NET core app that is set up to use .NET Aspire.
- Add .NET Aspire integrations to connect to Redis and implement caching.
- Configure the .NET Aspire integrations to meet specific requirements.
This article explores how to use two different types of ASP.NET Core caching using .NET Aspire and Redis:
- Output caching: A configurable, extensible caching method for storing entire HTTP responses for future requests.
- Distributed caching: A cache shared by multiple app servers that allows you to cache specific pieces of data. A distributed cache is typically maintained as an external service to the app servers that access it and can improve the performance and scalability of an ASP.NET Core app.
Prerequisites
To work with .NET Aspire, you need the following installed locally:
- .NET 8.0 or .NET 9.0
- An OCI compliant container runtime, such as:
- Docker Desktop or Podman. For more information, see Container runtime.
- An Integrated Developer Environment (IDE) or code editor, such as:
- Visual Studio 2022 version 17.9 or higher (Optional)
- Visual Studio Code (Optional)
- C# Dev Kit: Extension (Optional)
- JetBrains Rider with .NET Aspire plugin (Optional)
For more information, see .NET Aspire setup and tooling, and .NET Aspire SDK.
Create the project
- At the top of Visual Studio, navigate to File > New > Project....
- In the dialog window, enter .NET Aspire into the project template search box and select .NET Aspire Starter Application. Choose Next.
- On the Configure your new project screen:
- Enter a Project name of AspireRedis.
- Leave the rest of the values at their defaults and select Next.
- On the Additional information screen:
- Make sure .NET 9.0 is selected.
- Uncheck Use Redis for caching. You will implement your own caching setup.
- Select Create.
Visual Studio creates a new .NET Aspire solution that consists of the following projects:
- AspireRedis.Web - A Blazor UI project with default .NET Aspire configurations.
- AspireRedis.ApiService - A Minimal API with default .NET Aspire configurations that provides the frontend with data.
- AspireRedis.AppHost - An orchestrator project designed to connect and configure the different projects and services of your app.
- AspireRedis.ServiceDefaults - A .NET Aspire shared project to manage configurations that are reused across the projects in your solution related to resilience, service discovery, and telemetry.
Configure the App Host project
Add the 📦 Aspire.Hosting.Redis NuGet package to the
AspireRedis.AppHost
project:dotnet add package Aspire.Hosting.Redis
For more information, see dotnet add package or Manage package dependencies in .NET applications.
Update the Program.cs file of the
AspireRedis.AppHost
project to match the following code:var builder = DistributedApplication.CreateBuilder(args); var redis = builder.AddRedis("cache"); var apiservice = builder.AddProject<Projects.AspireRedis_ApiService>("apiservice") .WithReference(redis); builder.AddProject<Projects.AspireRedis_Web>("webfrontend") .WithExternalHttpEndpoints() .WithReference(apiservice) .WithReference(redis); builder.Build().Run();
The preceding code creates a local Redis container instance and configures the UI and API to use the instance automatically for both output and distributed caching. The code also configures communication between the frontend UI and the backend API using service discovery. With .NET Aspire's implicit service discovery, setting up and managing service connections is streamlined for developer productivity. In the context of this tutorial, the feature simplifies how you connect to Redis.
Traditionally, you'd manually specify the Redis connection string in each project's appsettings.json file:
{
"ConnectionStrings": {
"cache": "localhost:6379"
}
}
Configuring connection string with this method, while functional, requires duplicating the connection string across multiple projects, which can be cumbersome and error-prone.
Configure the UI with output caching
Add the .NET Aspire Stack Exchange Redis output caching integration packages to your
AspireRedis.Web
app:dotnet add package Aspire.StackExchange.Redis.OutputCaching
In the Program.cs file of the
AspireRedis.Web
Blazor project, immediately after the linevar builder = WebApplication.CreateBuilder(args);
, add a call to the AddRedisOutputCache extension method:builder.AddRedisOutputCache("cache");
This method accomplishes the following tasks:
- Configures ASP.NET Core output caching to use a Redis instance with the specified connection name.
- Automatically enables corresponding health checks, logging, and telemetry.
Replace the contents of the Home.razor file of the
AspireRedis.Web
Blazor project with the following:@page "/" @attribute [OutputCache(Duration = 10)] <PageTitle>Home</PageTitle> <h1>Hello, world!</h1> Welcome to your new app on @DateTime.Now
The integration include the
[OutputCache]
attribute, which caches the entire rendered response. The page also include a call to@DateTime.Now
to help verify that the response is cached.
Configure the API with distributed caching
Add the .NET Aspire Stack Exchange Redis distributed caching integration packages to your
AspireRedis.ApiService
app:dotnet add package Aspire.StackExchange.Redis.DistributedCaching
Towards the top of the Program.cs file, add a call to AddRedisDistributedCache:
builder.AddRedisDistributedCache("cache");
In the Program.cs file, add the following
using
statements:using System.Text; using System.Text.Json; using Microsoft.Extensions.Caching.Distributed;
In the Program.cs file, replace the existing
/weatherforecast
endpoint code with the following:app.MapGet("/weatherforecast", async (IDistributedCache cache) => { var cachedForecast = await cache.GetAsync("forecast"); if (cachedForecast is null) { var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast ( DateOnly.FromDateTime(DateTime.Now.AddDays(index)), Random.Shared.Next(-20, 55), summaries[Random.Shared.Next(summaries.Length)] )) .ToArray(); await cache.SetAsync("forecast", Encoding.UTF8.GetBytes(JsonSerializer.Serialize(forecast)), new () { AbsoluteExpiration = DateTime.Now.AddSeconds(10) }); ; return forecast; } return JsonSerializer.Deserialize<IEnumerable<WeatherForecast>>(cachedForecast); }) .WithName("GetWeatherForecast");
Test the app locally
Test the caching behavior of your app using the following steps:
- Run the app using Visual Studio by pressing F5.
- If the Start Docker Desktop dialog appears, select Yes to start the service.
- The .NET Aspire Dashboard loads in the browser and lists the UI and API projects.
Test the output cache:
- On the projects page, in the webfrontend row, click the
localhost
link in the Endpoints column to open the UI of your app. - The application will display the current time on the home page.
- Refresh the browser every few seconds to see the same page returned by output caching. After 10 seconds the cache expires and the page reloads with an updated time.
Test the distributed cache:
- Navigate to the Weather page on the Blazor UI to load a table of randomized weather data.
- Refresh the browser every few seconds to see the same weather data returned by output caching. After 10 seconds the cache expires and the page reloads with updated weather data.
Congratulations! You configured a ASP.NET Core app to use output and distributed caching with .NET Aspire.
.NET Aspire