Using Memcached as Distributed Cache in .NET Core

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
install docker image for 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
run docker image

Creating a Console Application

I will open Visual Studio 2019, after that I will create a new Console Application .NET Core.

new .Net Core console application

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
nuget packages

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.

console output from memcached

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