Caching has long been one of the most successful and proven strategies for enhancing application performance and scalability. There are several caching mechanisms in .NET Core including in-memory caching (IMemoryCache API), distributed caching (IDistributedCache API), and the new hybrid caching (HybridCache API), which will be a part of .NET 9 to be released in November this year.
Although these caching mechanisms may suffice in most scenarios, they often lack certain advanced features that you might need in your applications such as adaptive caching, eager refresh, and in-memory synchronization. Hence, you might often need solutions that are tailored to your requirements. Enter FusionCache.
This article discusses FusionCache, its features and benefits, and how we can work with it in ASP.NET Core applications.
What is FusionCache?
FusionCache is an open-source, simple, fast, and robust caching library with advanced resiliency features. It is an implementation of hybrid caching that is already being used by Microsoft. A hybrid cache can work either as a normal in-memory cache (L1) or, optionally, as a multi-level cache (L1 and L2) where L2 can be any implementation of the standard IDistributedCache interface, which allows a cache to be shared by multiple application servers.
The key features of FusionCache include the following:
- L1 and L2 caching
- Adaptive caching
- Conditional refresh
- Eager refresh
- Prevents cache stampedes
- Cache synchronization
- Fail-safe support
Create an ASP.NET Core Web API project in Visual Studio 2022
To create an ASP.NET Core Web API project in Visual Studio 2022, follow the steps outlined below.
- Launch the Visual Studio 2022 IDE.
- Click on “Create new project.”
- In the “Create new project” window, select “ASP.NET Core Web API” from the list of templates displayed.
- Click Next.
- In the “Configure your new project” window, specify the name and location for the new project. Optionally check the “Place solution and project in the same directory” check box, depending on your preferences.
- Click Next.
- In the “Additional Information” window shown next, select “.NET 8.0 (Long Term Support)” as the framework version and check the check box that says “Use controllers,” as we’ll be using controllers instead of minimal APIs in this project.
- Elsewhere in the “Additional Information” window, leave the “Authentication Type” set to “None” (the default) and make sure the check boxes “Enable OpenAPI Support,” “Configure for HTTPS,” and “Enable Docker” remain unchecked. We won’t be using any of those features here.
- Click Create.
We’ll use this ASP.NET Core Web API project to work with the FusionCache code examples given in the sections below.
Install the FusionCache NuGet package
To work with the FusionCache library, we’ll need to install the ZiggyCreatures.FusionCache NuGet package in the project. The latest stable version of FusionCache is 1.4.0.
Select the project in the Solution Explorer window, then right-click and select “Manage NuGet Packages.” In the NuGet Package Manager window, search for the ZiggyCreatures.FusionCache package and install it.
Alternatively, you can install the package via the NuGet Package Manager console by running the command below.
dotnet add package ZiggyCreatures.FusionCache
Configure FusionCache in ASP.NET Core
Once you have installed FusionCache into your project, you should register it as a service in the Program.cs file. Once registered, you can configure it by including the following code snippet in the Program.cs file.
builder.Services.AddFusionCache(options =>
{
options.DefaultEntryOptions = new FusionCacheEntryOptions
{
Duration = TimeSpan.FromMinutes(5),
Priority = CacheItemPriority.High
};
});
Create a new API controller in ASP.NET Core
We’ll now create a new API controller and implement FusionCache in there. To do this, follow the steps outlined below.
1. In the Solution Explorer window, select the project you created earlier, right-click, and select the Controllers folder.
2. Click “Add New Item.”
3. Select “API Controller – Empty” from the list of the project templates displayed.
4. Specify a name for your API controller, for example ProductController.
5. Click Add to complete the process.
This will create a new API controller in the Controllers folder of your project.
Create an action method in the controller class
Let us now create an action method in the ProductController class and write the following code in there.
[HttpGet("{productId}")]
public async Task GetProductById(int productId)
{
var cacheKey = $ "product_{productId}";
var cachedProduct = await _fusionCache.GetOrSetAsync
(cacheKey, async () =>
{
return await _productRepository.GetProductById(productId);
},
options => options.SetDuration(TimeSpan.FromMinutes(2)).
SetFailSafe(true));
if (cachedProduct == null)
{
return NotFound();
}
return Ok(cachedProduct);
}
Now refer to the GetProductById action method in the preceding code snippet — an asynchronous action method that returns a Product based on its Id. Note that you can take advantage of the GetOrSet method of FusionCache to retrieve data from the cache or the database. If the data is available in the cache, the cached data will be retrieved. If the data is not available in the cache, it will retrieved from the database.
Use constructor injection to create instances of the repository and cache
You should take advantage of dependency injection, in this case constructor injection, to inject instances of type IProductRepository and IFusionCache as shown in the code snippet given below.
private readonly IProductRepository _productRepository;
private readonly IFusionCache _fusionCache;
public ProductController(IFusionCache fusionCache,
IProductRepository productRepository)
{
_fusionCache = fusionCache;
_productRepository = productRepository;
}
Complete source code of FusionCache example
The complete source code of the ProductController class is given below for your reference.
using Microsoft.AspNetCore.Mvc;
using ZiggyCreatures.Caching.Fusion;
namespace FusionCacheExample.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ProductController : ControllerBase
{
private readonly IProductRepository _productRepository;
private readonly IFusionCache _fusionCache;
public ProductController(IFusionCache fusionCache,
IProductRepository productRepository)
{
_fusionCache = fusionCache;
_productRepository = productRepository;
}
[HttpGet("{productId}")]
public async Task GetProductById(int productId)
{
var cacheKey = $"product_{productId}";
var cachedProduct = await _fusionCache.GetOrSetAsync
(cacheKey, async () =>
{
return await _productRepository.GetProductById(productId);
},
options =>
options
.SetDuration(TimeSpan.FromMinutes(2))
.SetFailSafe(true)
);
if (cachedProduct == null)
{
return NotFound();
}
return Ok(cachedProduct);
}
}
}
Support for eager refresh in FusionCache
FusionCache includes a great feature called eager refresh that can help you keep your cache updated with the latest data while ensuring responsiveness at the same time. When you enable this feature, you can specify a custom duration for your cached data and also a percentage threshold, as shown in the code snippet below.
options => options.SetDuration(TimeSpan.FromMinutes(1))
options => options.SetEagerRefresh(0.5f)
Note how the cache duration has been set to 1 minute while the eager refresh threshold is set to 50% of the cache duration. When a new request arrives and your cached data is older than 50% of the cache duration (i.e., after 31 seconds), FusionCache will return the cached data and then refresh the cache in the background to ensure that the cache is updated.
Support for adaptive caching in FusionCache
Adaptive caching is yet another great feature in FusionCache that can adjust cache durations dynamically. It is the ability to change caching strategies based on contexts and conditions by taking into consideration the request rate, data update patterns, and system load. For example, adaptive caching can be used to adjust the cache duration automatically based on the last time stamp of the updated data.
The following code snippet illustrates how this can be achieved.
if (product is null)
{
Duration = TimeSpan.FromMinutes(3);
}
else if (order.LastUpdateTime > DateTime.UtcNow.AddDays(-1))
{
Duration = TimeSpan.FromMinutes(1);
}
else
{
Duration = TimeSpan.FromMinutes(10);
}
Basically, FusionCache is an improved version of Microsoft’s HybridCache API with additional features, more flexibility, and better resiliency. Microsoft has been using FusionCache for quite some time now.