Redis é um banco open source de armazenamento em memória, útil para comunicação assíncrona e armazenamento de cache. Conheça mais sobre a solução no site oficial!
Estrutura do Projeto
+---Redis
+---Factory
+---RedisFactory.cs
+---Interface
+---IRedisClient.cs
+---Models
+---RedisClient.cs
+---Program.cs
Implementando a biblioteca
Utilizaremos uma simples estrutura de factory para nos conectarmos a uma instância Redis utilizando a biblioteca StackExchange.Redis 2.7.17
IRedisClient.cs
using StackExchange.Redis;
namespace sample_redis_crud.Redis.Interface
{
public interface IRedisClient
{
string Url { get; }
string Port { get; }
string Pass { get; }
ConfigurationOptions? Options { get; }
ConnectionMultiplexer? Connection { get; }
IDatabase? Database { get; }
void SetOptions(string endpoint, string pass);
void SetConnection(ConfigurationOptions? options);
void SetDatabase(ConnectionMultiplexer conn);
}
}
Começando pelo nosso contrato, especificamos todas as propriedades necessárias para a implementação.
RedisClient.cs
using sample_redis_crud.Redis.Interface;
using StackExchange.Redis;
namespace sample_redis_crud.Redis.Models
{
public class RedisClient : IRedisClient
{
public RedisClient(string url, string port, string pass)
{
Url = url;
Port = port;
Pass = pass;
SetOptions($"{Url}:{Port}", Pass);
SetConnection(Options);
SetDatabase(Connection);
}
public string? Url { get; private set; }
public string? Port { get; private set; }
public string? Pass { get; private set; }
public ConfigurationOptions? Options { get; private set; }
public ConnectionMultiplexer? Connection { get; private set; }
public IDatabase? Database { get; private set; }
private void SetOptions(string endpoint, string pass)
{
Options = new ConfigurationOptions
{
EndPoints = { endpoint },
Password = pass,
AbortOnConnectFail = false
};
}
private void SetConnection(ConfigurationOptions? options)
{
if (options != null)
Connection = ConnectionMultiplexer.Connect(options);
}
private void SetDatabase(ConnectionMultiplexer? conn)
{
if (conn != null)
Database = conn.GetDatabase();
}
}
}
Na nossa classe, definimos os níveis de acesso e as rotinas dos nossos métodos, dos quais SetOptions
define os detalhes da nossa instância Redis (IP e senha de acesso), SetConnection
estabelece nossa conexão e SetDatabase
retorna nosso banco para realizarmos nossas operações.
RedisFactory.cs
using sample_redis_crud.Redis.Interface;
using sample_redis_crud.Redis.Models;
namespace sample_redis_crud.Redis.Factory
{
public static class RedisFactory
{
public static IRedisClient CreateInstance(string url, string port, string pass)
=> new RedisClient(url, port, pass);
}
}
Acima, implementamos nossa Factory, na qual retornamos apenas nossa interface IRedisClient, diminuindo o acoplamento do código.
Caso ache interessante, é possível criar uma biblioteca de classes com essa mesma estrutura e utilizá-la como um componente em diversos projetos!
Realizando operações
Para rodar nosso banco Redis, fiz uso de um servidor local em WSL 2 no Windows 10.
Inserindo chaves simples
Na nossa classe Program, criaremos nosso método de Insert de chave e valor.
using sample_redis_crud.Redis.Factory;
using sample_redis_crud.Redis.Interface;
using StackExchange.Redis;
namespace sample_redis_crud
{
public static class Program
{
public static void Main(string[] args)
{
var redisInstance = RedisFactory.CreateInstance("127.0.0.1", "6379", "");
redisInstance.Insert("1", "test@email.com");
}
static void Insert(this IRedisClient redisInstance, string key, string value)
=> redisInstance.Database?.StringSet(key, value);
}
}
No código, definimos nossa instância local e, acessando a propriedade Database, utilizamos o método StringSet
para inserção Obtemos o seguinte resultado:
127.0.0.1:6379> get 1
"test@email.com"
Inserindo chaves hash
Podemos optar por inserir uma hash, que abriga mais de um valor em uma única chave. A funcionalidade define cada valor como uma HashEntry, possuindo um nome de propriedade e valor.
using sample_redis_crud.Redis.Factory;
using sample_redis_crud.Redis.Interface;
using StackExchange.Redis;
namespace sample_redis_crud
{
public static class Program
{
public static void Main(string[] args)
{
var redisInstance = RedisFactory.CreateInstance("127.0.0.1", "6379", "");
var hash = new HashEntry[]
{
new HashEntry("ContactId", "123"),
new HashEntry("ContactName", "test"),
new HashEntry("ContactEmail", "test@email.com")
};
redisInstance.InsertHash("2", hash);
}
static void InsertHash(this IRedisClient redisInstance, string key, HashEntry[] hash)
=> redisInstance.Database?.HashSet(key, hash);
}
}
Utilizamos o método HashSet
, que recebe um array HashEntry[], no qual inserimos as propriedades ContactId, ContactName e ContactEmail com seus respectivos valores:
127.0.0.1:6379> hget 2 ContactId
"123"
127.0.0.1:6379> hget 2 ContactName
"test"
127.0.0.1:6379> hget 2 ContactEmail
"test@email.com"
Consultando dados inseridos
Para valores simples, podemos utilizar o método StringGet
, enviando a key do valor:
using sample_redis_crud.Redis.Factory;
using sample_redis_crud.Redis.Interface;
using StackExchange.Redis;
namespace sample_redis_crud
{
public static class Program
{
public static void Main(string[] args)
{
var redisInstance = RedisFactory.CreateInstance("127.0.0.1", "6379", "");
var value = redisInstance.Get("1");
Console.WriteLine($"Valor = {value}");
}
static string Get(this IRedisClient redisInstance, string key)
=> redisInstance.Database.StringGet(key);
}
}
Para consulta de hash, usaremos o método HashGet
, enviando a key que referencia as propriedades que inserimos:
using sample_redis_crud.Redis.Factory;
using sample_redis_crud.Redis.Interface;
using StackExchange.Redis;
namespace sample_redis_crud
{
public static class Program
{
public static void Main(string[] args)
{
var redisInstance = RedisFactory.CreateInstance("127.0.0.1", "6379", "");
var hash = redisInstance.GetHash("2");
if (hash is null) return;
foreach(var item in hash)
Console.WriteLine($"Prop = {item.Name}
Valor = {item.Value}
");
}
static HashEntry[]? GetHash(this IRedisClient redisInstance, string key)
=> redisInstance.Database?.HashGetAll(key);
}
}
Atualizando informações
Para atualizar registros, basta que utilizemos a chave do valor que desejamos atualizar e acionar o método Insert
e InsertHash
:
using sample_redis_crud.Redis.Factory;
using sample_redis_crud.Redis.Interface;
using StackExchange.Redis;
namespace sample_redis_crud
{
public static class Program
{
public static void Main(string[] args)
{
var redisInstance = RedisFactory.CreateInstance("127.0.0.1", "6379", "");
redisInstance.Insert("1", "newtest@email.com");
var hash = new HashEntry[]
{
new HashEntry("ContactId", "1234"),
new HashEntry("ContactName", "newtest"),
new HashEntry("ContactEmail", "newtest@email.com")
};
redisInstance.InsertHash("2", hash);
}
static void Insert(this IRedisClient redisInstance, string key, string value)
=> redisInstance.Database?.StringSet(key, value);
static void InsertHash(this IRedisClient redisInstance, string key, HashEntry[] hash)
=> redisInstance.Database?.HashSet(key, hash);
}
}
127.0.0.1:6379> get 1
"newtest@email.com"
127.0.0.1:6379> hget 2 ContactId
"1234"
127.0.0.1:6379> hget 2 ContactName
"newtest"
127.0.0.1:6379> hget 2 ContactEmail
"newtest@email.com"
Deletando informações
Para deletar valores, podemos utilizar o método StringGetDelete
, que busca o valor e, em seguida, o deleta do banco:
using sample_redis_crud.Redis.Factory;
using sample_redis_crud.Redis.Interface;
using StackExchange.Redis;
namespace sample_redis_crud
{
public static class Program
{
public static void Main(string[] args)
{
var redisInstance = RedisFactory.CreateInstance("127.0.0.1", "6379", "");
var value = redisInstance.Delete("1");
if (value is not null)
Console.WriteLine($"{value} Deletado!");
}
static string? Delete(this IRedisClient redisInstance, string key)
=> redisInstance.Database?.StringGetDelete(key);
}
}
Para valores Hash, podemos utilizar o método HashDelete
. O HashDelete
irá remover uma propriedade que for informada por vez, por isso, criaremos um loop para deletar cada hash existente:
using sample_redis_crud.Redis.Factory;
using sample_redis_crud.Redis.Interface;
using StackExchange.Redis;
namespace sample_redis_crud
{
public static class Program
{
public static void Main(string[] args)
{
var redisInstance = RedisFactory.CreateInstance("127.0.0.1", "6379", "");
redisInstance.DeleteHash("2");
}
static HashEntry[]? GetHash(this IRedisClient redisInstance, string key)
=> redisInstance.Database?.HashGetAll(key);
static void DeleteHash(this IRedisClient redisInstance, string key)
{
var hash = redisInstance.GetHash(key);
if (hash is null) return;
foreach(var item in hash)
redisInstance.Database?.HashDelete(key, item.Name);
}
}
}
Conclusão
Utilizar Redis como opção de armazenamento de cache pode auxiliar na comunicação entre serviços e diminuir acoplamento entre as aplicações. Além disso, existe a opção de estabelecer um “prazo de validade” para cada key que inserimos. Basta utilizar o método KeyExpire(key, timeSpan)
logo após inserir um registro, permitindo um controle maior do armazenamento interno.
Tratando-se de hash, podemos checar a existência de um certo atributo utilizando o método HashExists(key, atrName)
, em que atrName é o apelido da hash criada. Dessa forma, a aplicação retornará true em caso positivo.
Sinta-se livre para utilizar técnicas de injeção de dependência na criação de sua instância, estabelecendo boas práticas na arquitetura e design de código de seus serviços!
Confira o repositório do projeto de exemplo: https://github.com/Guilherme-Maciel/sample-redis-crud
Comentários
Postar um comentário