Using the In-Memory Cache with .NET Core Web API

Full source code available here.

If you need to store anything temporarily within an application, you should consider using the In-Memory Cache from Microsoft. In .NET Core it is much easier to use than its predecessor from Framework 4.x. You can store almost anything in it, in a type safe manner.

When adding an item to the cache you set the an expiration, this can be an absolute time, a sliding window or the combination of both. Choosing which one to use depends on your scenario.

When an item is removed from the cache a delegate can be called, you can use this for logging or some other purpose. Items can also be evicted when the cache is running low on memory.

In this example I’m going to show a simple usage example for the cache inside a .NET Core Web API application. Just a single line in startup.cs adds the cache to the dependency injection container.

1public void ConfigureServices(IServiceCollection services)
2{
3    services.AddMemoryCache();
4    services.AddMvc();
5}

Now I can access the cache from inside all my controllers by just adding an IMemoryCache parameter to the constructor.

1private readonly IMemoryCache _cache;
2public CountriesController(IMemoryCache memoryCache)
3{
4    _cache = memoryCache;
5}

I have a very simple GET method that takes a country code as its parameter and looks up full name of the country.

 1[HttpGet("{countryCode}")]
 2public async Task<IActionResult> Get(string countryCode)
 3{
 4    string country = await LookupCountryByCode(countryCode);
 5
 6    if (string.IsNullOrEmpty(country))
 7    {
 8        return NoContent();
 9    }
10    return Ok(country);
11}

And here is where I use the cache.

 1private async Task<string> LookupCountryByCode(string countryCode)
 2{
 3    if(!_cache.TryGetValue("ListOfCountries", out Dictionary<string, string> countries))
 4    {
 5        Console.WriteLine("Cache miss....loading from database into cache");
 6        countries =
 7            JsonConvert.DeserializeObject<Dictionary<string, string>>(
 8                await System.IO.File.ReadAllTextAsync("countrylist.json"));
 9
10        _cache.Set("ListOfCountries", countries, TimeSpan.FromSeconds(10));
11    }
12    else
13    {
14        Console.WriteLine("Cache hit");
15    }
16
17    return countries[countryCode];
18}

On line 3, I check if the list of countries is in the cache; I won’t be the first time through this method or if the cache entry has expired. Inside the if clause I load the list of countries from a json file, but you could load from a database or any other source. Then I add the list to the cache and set when the entry will expire, in this example it will expire 10 seconds after it was added.

If you want to use both an absolute expiration and sliding window you need to pass the MemoryCacheEntryOptions when adding an item to the cache.

1MemoryCacheEntryOptions options = new MemoryCacheEntryOptions
2{
3    AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(25), // cache will expire in 25 seconds
4    SlidingExpiration = TimeSpan.FromSeconds(5) // caceh will expire if inactive for 5 seconds
5};
6
7_cache.Set("ListOfCountries", countries, options);

Full source code available here.

comments powered by Disqus

Related