Using a distributed cache is key for building a high performant distributed system. Most of the time going to a distributed in-memory cache is better than hitting a centralized database. However, there are multiple options to choose from. But arguably the most popular ones are Memcached and Redis. In this post, I will explore using Memcached as a distributed cache in .NET Core Application.
Memcached Definition
Memcached is a distributed caching engine. Most importantly, it is free and open-sourced.
It is an in-memory key-value store for small chunks of arbitrary data (strings, objects).
For more information visit their website: https://memcached.org/
Installing Memched
Firstly, I will install Memcached in a docker container running in my Windows 10 desktop machine. Where I have a Windows Docker Client installed, running in the “Linux Container” mode.
docker pull memcached
Secondly, I will create and run a container from the image, exposing the port 11211; so I can access from the application I am about to build.
docker run -p 11211:11211 -d memcached
Creating a Console Application
I will open Visual Studio 2019, after that I will create a new Console Application .NET Core.
Adding Nuget Package
I will add the following NuGet packages:
- Firstly, I will add
Microsoft.Extensions.DependencyInjection
– For dependency injection - Secondly,
EnyimMemcachedCore
– Required for using Memcached - Finally,
Microsoft.Extensions.Logging
– Needed for EnyimMemcachedCore to have a Logger Factory
Creating IoC Container Configuration
I will create ContainerConfiguration class for register configuration for the application.
using Enyim.Caching.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
namespace Memched.Demo
{
internal static class ContainerConfiguration
{
public static IServiceProvider Configure()
{
var services = new ServiceCollection();
services.AddLogging();
services.AddEnyimMemcached(o => o.Servers = new List<Server> { new Server { Address = "localhost", Port = 11211 } });
return services.BuildServiceProvider();
}
}
}
CacheRepository and CacheProvider
In addition to the ContainerConfiguration
class, I will create a CacheRepository
and CacheProvider
classes. These classes will encapsulate the functionality of accessing Cache. This is important if we want to abstract the Cache provider from the rest of the application.
using Enyim.Caching;
namespace Memched.Demo
{
internal interface ICacheProvider
{
T GetCache<T>(string key);
}
internal class CacheProvider : ICacheProvider
{
private readonly IMemcachedClient memcachedClient;
public CacheProvider(IMemcachedClient memcachedClient)
{
this.memcachedClient = memcachedClient;
}
public T GetCache<T>(string key)
{
return memcachedClient.Get<T>(key);
}
}
}
using Enyim.Caching;
namespace Memched.Demo
{
internal interface ICacheRepository
{
void Set<T>(string key, T value);
}
internal class CacheRepository : ICacheRepository
{
private readonly IMemcachedClient memcachedClient;
public CacheRepository(IMemcachedClient memcachedClient)
{
this.memcachedClient = memcachedClient;
}
public void Set<T>(string key, T value)
{
// Setting cache expiration for an hour
memcachedClient.Set(key, value, 60 * 60);
}
}
}
Since I have added two new classes, therefore I will update the ContainerConfiguration
class to reflect the same.
using Enyim.Caching.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
namespace Memched.Demo
{
internal static class ContainerConfiguration
{
public static IServiceProvider Configure()
{
var services = new ServiceCollection();
services.AddLogging();
services.AddEnyimMemcached(o => o.Servers = new List<Server> { new Server { Address = "localhost", Port = 11211 } });
services.AddSingleton<ICacheProvider, CacheProvider>();
services.AddSingleton<ICacheRepository, CacheRepository>();
return services.BuildServiceProvider();
}
}
}
Update to Program class
Finally, I will update the Program class to set and get cache.
using System;
using System.Threading;
using Microsoft.Extensions.DependencyInjection;
namespace Memched.Demo
{
class Program
{
static void Main(string[] args)
{
var provider = ContainerConfiguration.Configure();
Console.WriteLine("Set cache");
var cacheRepository = provider.GetService<ICacheRepository>();
// Set cache
cacheRepository.Set("Key_1", "123");
Console.WriteLine("Sleep for 2 minutes");
// Sleep for 2 Minutes
Thread.Sleep(1000 * 60 * 2);
Console.WriteLine("Get cache");
// Get cache
var cacheProvider = provider.GetService<ICacheProvider>();
Console.WriteLine($"Value from cache {cacheProvider.GetCache<string>("Key_1")}");
Console.ReadLine();
}
}
}
After that, I will run the application.
Conclusion
In conclusion, using Memcached with .NET Core is seamless. With the Docker container install, the experience was really smooth.
Above all, here is the link to the GitHub code: https://github.com/choudhurynirjhar/memcached-demo.
In addition, below is the recorded YouTube video: https://youtu.be/yQ8Kwx9M_Hg