Sam
Sam

Reputation: 30342

Caching data in ASP.NET Core app running on Azure without Redis

There are a few things I'd like to cache without relying on Redis. My app is an ASP.NET Core API app running on Azure App Service.

For example, I create a list of countries from

CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures);

I can save this in Redis but it'll cost money and this is not a list that changes often and is produced from the framework so even if I'm running multiple instances of my API app, lists will be identical.

How do I save this in memory without Redis? I can call a method that generates this list in my Startup.cs but where do I store it and how do I retrieve it?

Upvotes: 2

Views: 2013

Answers (1)

NightOwl888
NightOwl888

Reputation: 56869

AspNetCore has a built-in memory cache that you can use to store pieces of data that are shared between requests.

Register the cache at startup...

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMemoryCache();
        services.AddMvc();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseMvcWithDefaultRoute();
    }
}

And you can inject it like...

public class HomeController : Controller
{
    private IMemoryCache _cache;

    public HomeController(IMemoryCache memoryCache)
    {
        _cache = memoryCache;
    }

    public IActionResult Index()
    {
        string cultures = _cache[CacheKeys.Cultures] as CultureInfo[];

        return View();
    }

To make it work application wide, you can use a facade service with strongly-typed members combined with some sort of cache refresh pattern:

  1. Attempt to get the value from the cache
  2. If the attempt fails
    • Lookup the data from the data source
    • Repopulate the cache
  3. Return the value

public CultureInfo[] Cultures { get { return GetCultures(); } }

private CultureInfo[] GetCultures()
{
    CultureInfo[] result;

    // Look for cache key.
    if (!_cache.TryGetValue(CacheKeys.Cultures, out result))
    {
        // Key not in cache, so get data.
        result = CultureInfo.GetCultures(CultureTypes.SpecificCultures);

        // Set cache options.
        var cacheEntryOptions = new MemoryCacheEntryOptions()
            // Keep in cache for this time, reset time if accessed.
            .SetSlidingExpiration(TimeSpan.FromMinutes(60));

        // Save data in cache.
        _cache.Set(CacheKeys.Cultures, result, cacheEntryOptions);
    }

    return result;
}

Of course, you could clean that up by making it into a service that accepts the cache as a dependency which you can inject wherever it is needed, but that is the general idea.

Note also there is a distributed cache in case you want to share data between web servers.

Upvotes: 2

Related Questions