Implement Redis Cache in .Net Core API

In the Asp.Net Core API, you can add and remove caches utilising distributed redis caching.

January 2, 2025

using Microsoft.Extensions.Caching.Distributed;
using StackExchange.Redis;
 
namespace yourproject.Cache
{
    public interface IRedisCacheService
    {
        Task<TGetOrSetRedisCacheAsync<T>(string keyFunc<Task<T>> fetchDataTimeSpanexpiry = null);
        Task SetRedisCacheAsync<T>(string keyT dataTimeSpanexpiration = null);
        Task RemoveRedisCacheAsync(string key);
        Task RemoveRedisKeysContainingAsync(string basekeystring key);
    }
 
    public class RedisCacheService : IRedisCacheService
    {
        private readonly IDistributedCache _redisCache;
        private readonly ConnectionMultiplexer _redisConnection;
 
        public RedisCacheService(IDistributedCache cacheConnectionMultiplexer redisConnection)
        {
            _redisCache = cache;
            _redisConnection = redisConnection;
        }
 
        public async Task<TGetOrSetRedisCacheAsync<T>(string keyFunc<Task<T>> fetchDataTimeSpanexpiry = null)
        {
            var cachedValue = await _redisCache.GetStringAsync(key);
 
            if (cachedValue != null)
                return JsonConvert.DeserializeObject<T>(cachedValue);
 
            var data = await fetchData();
 
            await SetRedisCacheAsync(keydataexpiry);
 
            return data;
        }
 
        public async Task SetRedisCacheAsync<T>(string keyT dataTimeSpanexpiry = null)
        {
            var serializedData = JsonConvert.SerializeObject(data);
 
            var cacheOptions = new DistributedCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow = expiry ?? TimeSpan.FromMinutes(1440)
            };
 
            await _redisCache.SetStringAsync(keyserializedDatacacheOptions);
        }
 
        public async Task RemoveRedisCacheAsync(string key)
        {
            await _redisCache.RemoveAsync(key);
        }
 
        public async Task RemoveRedisKeysContainingAsync(string basekeystring key)
        {
            var server = _redisConnection.GetServer(_redisConnection.GetEndPoints().First());
            var keys = server.Keys(pattern$"*{basekey}*").ToArray(); 
 
            foreach (var rediskey in keys)
            {
                if (rediskey.ToString().Contains(basekey) && rediskey.ToString().Contains(key))
                {
                    await _redisCache.RemoveAsync(rediskey.ToString());
                }
            }
        }
    }
}

Register services in the Program.cs file.

// Register RedisCacheService
string redisCacheDbString = Environment.GetEnvironmentVariable("redisConnectionString")!;
 
builder.Services.AddSingleton(sp =>
{
    return ConnectionMultiplexer.Connect(redisCacheDbString);
});
 
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = redisCacheDbString;
});
 
builder.Services.AddSingleton<IRedisCacheServiceRedisCacheService>();

Add and Remove cache in Controllers.cs

using yourproject.Cache;
using yourproject.Entities;
 
namespace yourproject.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class UserController : ControllerBase
    {
        private readonly IUserService _serviceProvider;
        private readonly IRedisCacheService _cachingService;
 
        public UserController(IUserService serviceProviderIRedisCacheService cachingService)
        {
            _serviceProvider = serviceProvider;
            _cachingService = cachingService;
        }
 
        [HttpGet("{id}")]
        public async Task<IActionResultGet(int id)
        {
            var cacheKey = $"user_{id}";
 
            var response = await _cachingService.GetOrSetRedisCacheAsync(
                cacheKey,
                () => _serviceProvider.GetUserByID()
            );
 
            return response == null ? NotFound() : Ok(response);
        }
 
        [HttpGet("GetAllUser")]
        public async Task<IActionResultGetAllUser()
        {
            var cacheKey = $"user_getall";
 
            var response = await _cachingService.GetOrSetRedisCacheAsync(
                cacheKey,
                () => _serviceProvider.GetAllUser()
            );
 
            return response == null ? NotFound() : Ok(response);
        }
 
        [HttpPut]
        public async Task<IActionResultEdit([FromBodyUserRegisterItemModel user)
        {
            var validation = true// custome logic. like validate user role, etc
            if (validation)
            {
                //Remove specific key
                await _cachingService.RemoveRedisCacheAsync($"user_{user.ID}");
 
                //Remove multiple keys using contains.
                await _cachingService.RemoveRedisKeysContainingAsync("user_"user.ID);
 
                return Ok(await _serviceProvider.UpdateUser(User));
            }
            else
            {
                return BadRequest();
            }
        }
    }
}

Post Comments(0)

Leave a reply

Will not be displayed in comment box .

Loading...