Estimados devs, esta vez toca hacer un taller realista, primero te explicaré los conceptos, luego lo implementaremos, allá vamos!
Qué es Redis?
Redis (Remote Dictionary Server) es una base de datos en memoria de tipo key-value (clave-valor).
Se usa sobre todo para caché, colas de mensajes, contadores, sesiones o bloqueos distribuidos, porque es extremadamente rápido (microsegundos por operación, ojo, son microsegundos no milisegundos 🤯).
En otras palabras: Redis no reemplaza tu base de datos relacional (SQL Server, PostgreSQL, etc.), sino que la complementa para reducir la carga y acelerar las respuestas.
Para qué sirve?
En un API REST hecho con .NET podrías utilizarlo para:
- Guardar repsuestas cacheadas de endpoints costosos
- Evitar leer siempre desde la base de datos
- Mantener tokens o datos de sesión
- Compartir datos de forma rápida entre microservicios
Aquí te mostraré un ejemplo:
public class ProductService (RedisService redisService, ProductRepository productRepository) : IProductService
{
public async Task<Product?> GetProduct(int id)
{
var cacheKey = $"product:{id}";
var cached = await redisService.GetAsync<Product>(cacheKey);
if (cached is not null)
return cached;
var product = await productRepository.GetByIdAsync(id);
await redisService.SetAsync(cacheKey, product, TimeSpan.FromMinutes(5));
return product;
}
}
Esa puede ser una típica clase de servicio.
Lo que está pasando allí es que antes de ir a la base de datos (mediante productRepository) busca si existe en Redis y si existe lo trae, si no existe recién viaja a la base de datos, cachea esa información (para que esté disponible en siguientes requests) y retorna el valor.
Integrar Redis en Clean Architecture
Redis debe estar en tu capa de Infraestructura, nunca en Application o mucho menos en dominio ni Presentación.
El motivo es porque de esa manera mantenemos independencia de frameworks o librerías en el core de nuestro sistema, como ya sabes, el Core en Clean Architecture es Dominio y Aplicación.
Otro motivo es porque Redis es una implementación, no una abstracción y las implementaciones son de bases de datos, caché, time providers, emails, etc. van en infraestructura por definición y para mantener la regla de dependencias hacia adentro y no hacia afuera, esto está relacionado con el principio de Inversión de Dependencias.
Más información de Clean Architecture aquí.
A continuación te enseñaré a implementar un caché usando Redis. Las tecnologías y conocimientos que deberás manejar o al menos estar familiarizado son:
- Clean Architecture
- Redis (bueno esto aquí lo aprenderás 🤭)
- Inyección de dependencias
- Azure Cache for Redis
- Docker
Implementación en .NET
Suponiendo que tienes tu proyecto con Clean Architecture así:

Paquetes necesarios
En tu proyecto MyStore.Infrastructure instala lo siguiente:
- dotnet add package stackexchange.redis
Interfaz en Application
En la capa de Application deberás crear la interfaz para un servicio que se encargará del caché:
public interface ICacheService
{
Task<T?> GetAsync<T>(string key);
Task SetAsync<T>(string key, T value, TimeSpan? expiration = null);
Task RemoveAsync(string key);
}
Implementa Redis en Infrastructure
Ahora implementaremos esa interfaz en la capa de Infraestructura con la siguiente clase:
public class RedisCacheService : ICacheService
{
private readonly IDatabase _database;
public RedisCacheService(IConnectionMultiplexer connection)
{
_database = connection.GetDatabase();
}
public async Task<T?> GetAsync<T>(string key)
{
var value = await _database.StringGetAsync(key);
if (value.IsNullOrEmpty) return default;
return JsonConvert.DeserializeObject<T>(value!);
}
public async Task SetAsync<T>(string key, T value, TimeSpan? expiration = null)
{
var json = JsonConvert.SerializeObject(value);
await _database.StringSetAsync(key, json, expiration);
}
public async Task RemoveAsync(string key)
{
await _database.KeyDeleteAsync(key);
}
}
Registra Redis
En Program.cs o donde sea que registres tus servicios registramos Redis:
var redisConnection = configuration.GetConnectionString("RedisConnection");
services.AddSingleton<IConnectionMultiplexer>(sp => ConnectionMultiplexer.Connect(redisConnection));
services.AddScoped<ICacheService, RedisCacheService>();
Configura cadena de conexión
Como ya te he mencionado Redis es una base de datos, sólo que trabaja en memoria, así que necesitarás alojarla en un servidor ya sea en local o en la nube, así que podrías desplegar un contenedor de docker para tener Redis disponible localmente o podrías utilizar Azure Cache for Redis (o Azure Managed Redis) si prefieres usar la nube de Azure. Sea cual sea la opción elegida, tendrás que obtener la cadena de conexión para usarla en tu aplicación.
En ambiente development o desarrollo podrías almacenar la cadena de conexión el el appsettings.development.json, sin embargo en un ambiente productivo ni se te ocurra, allí tendrías que ponerlo como variable de ambiente en appservice o utilizar algún servicio como KeyVault.
"ConnectionStrings": {
"redisConnection": "YourRedisServer:6380,password=YourPassword,ssl=True,abortConnect=False"
},
Inyectalo y úsalo
Ahora ya puedes usarlo, podría ser en una clase de Servicio o en un Handler si estás usando patrones como mediador o CQRS.
Aquí te muestro un ejemplo de cómo quedaría si lo empleas en un QueryHandler utilizando el patrón mediador y CQRS:
public class ListStudiosQueryHandler : IRequestHandler<ListStudiosQuery, ErrorOr<List<Studio>>>
{
private readonly IStudiosRepository studiosRepository;
private readonly ISubscriptionsRepository subscriptionsRepository;
private readonly ICacheService cacheService;
public ListStudiosQueryHandler(
IStudiosRepository studiosRepository,
ISubscriptionsRepository subscriptionsRepository,
ICacheService cacheService)
{
this.studiosRepository = studiosRepository;
this.subscriptionsRepository = subscriptionsRepository;
this.cacheService = cacheService;
}
public async Task<ErrorOr<List<Studio>>> Handle(ListStudiosQuery query, CancellationToken cancellationToken)
{
if (!await subscriptionsRepository.ExistsAsync(query.SubscriptionId))
return Error.NotFound(description: "Subscription not found");
var key = $"subscription:{query.SubscriptionId}";
var cached = await cacheService.GetAsync<List<Studio>>(key);
if (cached != null)
return cached;
var studios = await studiosRepository.ListBySubscriptionIdAsync(query.SubscriptionId);
await cacheService.SetAsync(key, studios, TimeSpan.FromMinutes(1));
return studios;
}
}
Sin embargo, también lo puedes usar como te lo mostré más arriba, en una clase de servicio más sencillita.
Ahora ya puedes disfrutar de las ventajas de Redis y también de haber mejorado tus skills.
Nos vemos en la próxima devs, y ya sabes, si te ha gustado este artículo compártelo con todo tu equipo de ingeniería 😉
Créditos de imagen de portada: Foto de Lukas Boekhout en Unsplash
