In-Memory and Distributed Caching in ASP.Net Core MVC Application

Caching helps in improving performance of an application by replicating the data (otherwise which has to be fetched from database or any other source). ASP.Net Core supports both in-memory and distributed caching. In-memory caching holds the copy of data in local server’s memory, where as distributed cache maintains cache in a centralized location which is accessible by servers in cluster. In this tutorial we are going to see how to implement both in-memory and distributed caching in ASP.Net Core MVC application.

NOTE: Updated this tutorial on 2/26/2017 with MSBuild based Dotnet SDK.

Create an ASP.Net Core Application using VS 2017. I am using following version of Dotnet SDK which is based on MSBuild/CSProj (remember that previous versions of ASP.Net Core are based on Project.json/XProj.).

image

Once the application is created, we can add the cache service (from Microsoft.Extensions.Caching.Memory) to ConfigureServices method in Startup class.

services.AddMemoryCache();

To add items to the cache in our application, we will use IMemoryCache which can be injected to any class (for example Controller) as shown below.

private IMemoryCache _memoryCache;
public HomeController(IMemoryCache memoryCache)
{
    _memoryCache = memoryCache;
}

Now lets create a type which will be stored in cache. I created below class for demonstration.

public class UserContent
{
    public string Username { get; set; }
    public string Email { get; set; }
    public List<string> Roles { get; set; }
}

Then we can Set and Get values from cache as shown below. IMemoryCache.Set() takes the key, value and MemoryCacheEntryOptions.

MemoryCacheEntryOptions is used to configure the cache entry by setting the Priority (High, Low, NeverRemove, Normal), sliding expiration, absolute expiration, expiration token, eviction callback and other dependencies. Priority is used to manage cache items at the time of memory congestion (high priority items will be preserved than low priority items). Sliding expiration sets how long the cache item can be inactive before removal. Absolute expiration sets the expiration for cache item (Absolute expiration takes precedence over sliding expiration, means sliding expiration cannot make cache entry life to go beyond absolute expiration). Expiration token is used to trigger expiration for a cache entry by calling token’s Cancel event, this is helpful when we have to remove a cache item based on some external dependencies. Eviction callback is triggered when the cache item is evicted.

public IActionResult Index()
{
    var cts = new CancellationTokenSource();
    _memoryCache.Set("User", new UserContent
    {
        Username = "Intstrings",
        Email = "intstrings@gmail.com",
        Roles = new List<string> { "Admin" }
    }, new MemoryCacheEntryOptions()
            .SetPriority(CacheItemPriority.High)
            .SetSlidingExpiration(TimeSpan.FromMinutes(10))
            .SetAbsoluteExpiration(TimeSpan.FromMinutes(30))
            .AddExpirationToken(new CancellationChangeToken(cts.Token))
            .RegisterPostEvictionCallback(
                (echoKey, value, reason, substate) =>
                {
                    // Triggered when this cache item is evicted.
                }));
    return Json(true);
}

public IActionResult About()
{
    UserContent user;
    _memoryCache.TryGetValue("User", out user);
    return Json(user);
}

Now using Postman tool, lets make a request to Index action. We should see below response.

image

Lets make a request to About Action. We should see below response with UserContent data which has been loaded from cache and sent back in JSON format.

image

Now lets see how we can use distributed cache like Redis in our ASP.Net Core Application.

Follow this tutorial to install and run Redis server on local machine – JumpStart # 45 – Redis Cache based Session State in ASP.Net Core MVC Application. On successful running of Redis Server, Install below package dependency.

<ItemGroup>
  <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
  <PackageReference Include="Microsoft.AspNetCore" Version="1.0.3" />
  <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.0.2" />
  <PackageReference Include="Microsoft.AspNetCore.Session" Version="1.1.0" />
  <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.0.1" />
  <PackageReference Include="Microsoft.Extensions.Caching.Redis" Version="1.1.0" />
  <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.0.1" />
  <PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="1.0.1" />
</ItemGroup>

Now instead of using In-memory Cache service, we will use Distributed Redis Cache service in ConfigureServices method of Startup class.

services.AddDistributedRedisCache(options =>
{
    options.Configuration = "localhost";
    options.InstanceName = "RedisInstance";
});

Lets change the implementation of Cache in Controller from IMemoryCache to IDistributedCache.

private IDistributedCache _memoryCache;
public HomeController(IDistributedCache memoryCache)
{
    _memoryCache = memoryCache;
}

We are going to change our controller actions (Index and About) to support IDistributedCache. We can notice that IDistributedCache API is little different from IMemoryCache.  

public IActionResult Index()
{
    _memoryCache.SetString("User", JsonConvert.SerializeObject(new UserContent
    {
        Username = "Intstrings",
        Email = "intstrings@gmail.com",
        Roles = new List<string> { "Admin" }
    }), new DistributedCacheEntryOptions()
            .SetSlidingExpiration(TimeSpan.FromMinutes(10))
            .SetAbsoluteExpiration(TimeSpan.FromMinutes(30)));
    return Json(true);
}

public IActionResult About()
{
    UserContent user = JsonConvert.DeserializeObject<UserContent>(_memoryCache.GetString("User"));
    return Json(user);
}

When we run the application, we will see similar output (as of In-memory cache scenario) in postman. If we run the redis-cli from command line prompt, we can check the Redis key value pairs. To check the key we just inserted, use keys * command. Then to check the value associated with the key, we have to use hgetall key.

image

That’s it for now. Happy Coding and Stay Tuned!!!

You may also like...