StackExchange.Redis – criando um extender para armazenar objetos de forma transparente

Facebooktwittergoogle_plusredditpinterestlinkedinmail

Em nosso último post, StackExchange.Redis – acessando Redis com C#, vimos como acessar o Redis usando C#, usando o pacote StackExchange.Redis. Porém, esse pacote, não traz métodos para inserir e recuperar objetos do Redis de forma automática e transparente, exigindo que seja feita a serialização/deserialização do objeto em uma string cada vez que usamos o SET/GET, o que não é um problema, pois o pacote StackExchange.Redis faz muito bem o que se propõe, que é fazer a interface com o Redis. E se lembrarmos dos tipos suportados pelo Redis, falamos disso aqui, vamos ver que ele não suporta objetos diretamente, e sim strings, exigindo que seja feita a serialização/deserialização dos objetos.

O que vamos ver hoje aqui, é como criar um Extender para o StackExchange.Redis, que irá nos permitir trabalhar com objetos tipados de forma transparente, abstraindo a serialização/deserialização.

Para começar, vamos criar uma nova aplicação console, e fazer a instalação do pacote StackExchange.Redis e do pacote Json.net (vamos precisar dele para fazer a serialização/deserialização) usando o NuGet Package Manager. Da mesma forma que fizemos em nosso último post. Feito isso, vamos criar uma classe chamada Desenvolvedor, para utilizarmos em nosso exemplo do Extender que estamos criando:

namespace StackExchangeRedisDemo
{
    public class Desenvolvedor
    {
        public string Nome { get; set; }
        public string Linguagem { get; set; }
        public int AnosExperiencia { get; set; }

        public override string ToString() => $"Nome: {Nome} - Linguagem: {Linguagem} - AnosExperiencia: {AnosExperiencia}";
    }
}

Fizemos o override do método ToString, para retornar o valor de todas as nossas propriedades, que vamos usar para imprimir no console e garantir que nosso Extender funciona.

Agora vamos alterar a classe Program, e como fizemos em nosso outro exemplo, vamos começar conectando ao Redis:

ConnectionMultiplexer connectionRedis = ConnectionMultiplexer.Connect("localhost:13919,password=senhadoredis");
IDatabase clientRedis = connectionRedis.GetDatabase();

Agora vamos instanciar um objeto do tipo Desenvolvedor, para adcionarmos ao Redis:

Desenvolvedor devNinja = new Desenvolvedor();
devNinja.Nome = "Desenvolvedor Ninja";
devNinja.Linguagem = "C#";
devNinja.AnosExperiencia = 15;

Agora vamos criar o nosso Extender, para isso crie uma nova classe com o nome StackExchangeRedisExtension, e declare-a como estática:

public static class StackExchangeRedisExtension

Vamos agora criar dois métodos de extensão, um GET e um SET, mas antes de criá-los, vamos criar os métodos que irão fazer a serialização e a deserialização dos objetos. Coloque o seguinte código na classe StackExchangeRedisExtension:

private static string ToJson(object value)
{
    return JsonConvert.SerializeObject(value);
}

private static T FromJson<T>(string value)
{
    return JsonConvert.DeserializeObject<T>(value);
}

Os métodos acima transformam um objeto em um Json, e criam um objeto a partir de um Json.

Agora sim, vamos criar o nosso método SET:

public static bool Set(this IDatabase cache, string key, object value)
{
    return cache.StringSet(key, ToJson(value));
}

O que fazemos aqui, é chamar o método StringSet, que insere uma string no Redis, e o que fazemos aqui, é chamar nosso método ToJson, passando um object, para que seja transformado em uma string, e armazenado no Redis. A diferença é o uso da palavra this na declaração do parâmetro cache, o que transforma nosso método em um extension method para objetos do tipo IDatabase. Ou seja, podemos chamar nosso método a partir de um objeto do tipo IDatabase, como se nosso método tivesse sido criado junto com a interface IDatabase.

Agora vamos implementar o GET:

public static T Get<T>(this IDatabase cache, string key)
{
    return FromJson<T>(cache.StringGet(key));
}

Usamos novamente o this para o parâmetro cache, e definimos um retorno do tipo T usando Generics para tiparmos nosso retorno. E usamos o método FromJson, para transformar a string retornada pelo médoto StringGet em objeto novamente.

Nosso Extender está pronto, agora podemos voltar a nossa classe Program, para utilizarmos nosso Extender. Vamos agora colocar nosso objeto Desenvolvedor no Redis, e para isso faremos:

clientRedis.Set("desenvolvedor", devNinja);

Veja que usamos o objeto clientRedis, que é do tipo IDatabase, e chamamos o método Set, que criamos em nossa classe, como se fosse declarado na interface IDatabase. Nosso método vai converter Desenvolvedor em uma string no usando o padrão Json, e adicionar ao Redis.

Agora vamos obter o valor da chave que definimos acima, e colocá-la em um objeto do tipo Desenvolvedor, e imprimirmos no console o valor de suas propriedades para vermos se serão os mesmos que definimos no início de nosso programa:

Desenvolvedor devNinjaGet = clientRedis.Get<Desenvolvedor>("desenvolvedor");
Console.WriteLine(devNinjaGet.ToString());

Em nosso console serão impressos os valores que definimos no início do nosso programa:

Nome: Desenvolvedor Ninja - Linguagem: C# - AnosExperiencia: 15

E por fim, vamos encerrar a conexão com o Redis:

connectionRedis.Close();

O código completo de nosso Extender fica assim:

using Newtonsoft.Json;
using StackExchange.Redis;

namespace StackExchangeRedisDemo
{
    public static class StackExchangeRedisExtension
    {
        private static string ToJson(object value)
        {
            return JsonConvert.SerializeObject(value);
        }

        private static T FromJson<T>(string value)
        {
            return JsonConvert.DeserializeObject<T>(value);
        }

        public static bool Set(this IDatabase cache, string key, object value)
        {
            return cache.StringSet(key, ToJson(value));
        }

        public static T Get<T>(this IDatabase cache, string key)
        {
            return FromJson<T>(cache.StringGet(key));
        }
    }
}

E nossa classe Program ficou assim:

using StackExchange.Redis;
using System;

namespace StackExchangeRedisDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ConnectionMultiplexer connectionRedis = ConnectionMultiplexer.Connect("pub-redis-13919.us-east-1-2.5.ec2.garantiadata.com:13919,password=salamandraverde"))
            {
                IDatabase clientRedis = connectionRedis.GetDatabase();

                Desenvolvedor devNinja = new Desenvolvedor();
                devNinja.Nome = "Desenvolvedor Ninja";
                devNinja.Linguagem = "C#";
                devNinja.AnosExperiencia = 15;

                clientRedis.Set("desenvolvedor", devNinja);

                Desenvolvedor devNinjaGet = clientRedis.Get<Desenvolvedor>("desenvolvedor");
                Console.WriteLine(devNinjaGet.ToString());

                connectionRedis.Close();
            }
        }
    }
}

Dessa vez não coloquei o projeto de exemplo desse post no GitHub, porém, criei um Extender mais completo, com mais métodos e com teste unitário, que pode ser baixado e utilizado em seus projetos livremente: https://github.com/rdakar/StackExchange.Redis.Extender

Além disso, publiquei o Extender como um pacote do NuGet, para quem preferir apenas instalar o pacote e utilizá-lo, sem necessidade de baixar os fontes. Você pode encontrá-lo na página do NuGet: https://www.nuget.org/packages/StackExchange.Redis.Extender/

Para instalá-lo em seu projeto, basta digitar a linha abaixo no console do NuGet:

Install-Package StackExchange.Redis.Extender
Facebooktwittergoogle_plusredditpinterestlinkedinmail

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *