Exercício – Conectar um aplicativo ao cache
Agora que temos um Cache Redis criado no Azure, vamos criar um aplicativo para usá-lo. Verifique se você tem as informações de cadeia de conexão do portal Azure.
Observação
O Cloud Shell integrado está disponível no lado direito. Você pode usar o prompt de comando para criar e executar o código de exemplo que estamos construindo aqui, ou realizar essas etapas localmente se tiver um ambiente de desenvolvimento .NET Core configurado.
Criar um aplicativo de console
Usaremos um aplicativo de console simples para focarmos na implementação do Redis.
No Cloud Shell, crie um aplicativo de console .NET Core e nomeie-o como
SportsStatsTracker
.dotnet new console --name SportsStatsTracker
Altere o diretório atual para a pasta do novo projeto.
cd SportsStatsTracker
Adicionar a cadeia de conexão
Vamos adicionar a cadeia de conexão que obtivemos do portal Azure no código. Nunca armazene esse tipo de credencial no seu código-fonte. Para simplificar esse exemplo, vamos utilizar um arquivo de configuração. Uma abordagem melhor para um aplicativo de servidor no Azure seria utilizar o Azure Key Vault com certificados.
Crie um novo arquivo appsettings.json para adicionar ao projeto.
touch appsettings.json
Abra o editor de código inserindo
code .
na pasta do projeto. Caso esteja trabalhando localmente, use o Visual Studio Code. As etapas aqui serão alinhadas principalmente ao uso.Selecione o arquivo appsettings.json no editor e adicione o texto a seguir. Cole a cadeia de conexão no valor da configuração.
{ "CacheConnection": "[value-goes-here]" }
Salve as alterações.
Importante
Sempre que você colar ou alterar o código em um arquivo no editor, salve usando o menu ... ou a tecla de atalho (Ctrl + S no Windows e no Linux, e Cmd + S no macOS).
Selecione o arquivo SportsStatsTracker. csproj no editor para abri-lo.
Adicione o seguinte bloco de configuração
<ItemGroup>
ao elemento raiz<Project>
abaixo do elemento<PropertyGroup>
. Esta configuração incluirá o novo arquivo no projeto e o copiará na pasta de saída. As instruções neste bloco garantem que o arquivo de configuração de aplicativos seja colocado no diretório de saída quando o aplicativo for compilado/criado.<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> ... </PropertyGroup> <ItemGroup> <None Update="appsettings.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> </ItemGroup> </Project>
Salve o arquivo.
Importante
Se você não salvar o arquivo, perderá a alteração ao adicionar o pacote mais tarde.
Adicionar suporte para ler um arquivo de configuração JSON
Um aplicativo .NET Core exige pacotes NuGet adicionais para ler um arquivo de configuração JSON.
Na seção do prompt de comando da janela, adicione uma referência ao pacote NuGet Microsoft.Extensions.Configuration.Json:
dotnet add package Microsoft.Extensions.Configuration.Json
Adicionar um código para ler o arquivo de configuração
Agora que adicionamos as bibliotecas necessárias para habilitar a configuração de leitura, é necessário habilitar essa funcionalidade no aplicativo de console.
Selecione Program.cs no editor. Substitua o conteúdo do arquivo pelo seguinte código:
using Microsoft.Extensions.Configuration; namespace SportsStatsTracker { class Program { static void Main(string[] args) { var config = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .Build(); } } }
A instrução
using
permite acessar as bibliotecas para ler a configuração. O código no métodoMain
inicializa o sistema de configuração para ler o arquivo appsettings.json.
Obtenha a cadeia de conexão da configuração
Em Program.cs, no final do método Main, utilize a nova variável config para recuperar a cadeia de conexão e armazená-la em uma nova variável denominada connectionString.
A variável config tem um indexador no qual você pode passar uma cadeia de caracteres para recuperação do seu arquivo appSettings.json.
string connectionString = config["CacheConnection"];
Adicionar suporte para o cliente Redis cache .NET
Em seguida, vamos configurar o aplicativo de console para utilizar o cliente StackExchange.Redis para .NET.
Adicione o pacote NuGet StackExchange.Redis ao projeto utilizando o prompt de comando na parte inferior do editor do Cloud Shell.
dotnet add package StackExchange.Redis
Selecione Program.cs no editor e adicione um
using
para o namespace StackExchange.Redisusing StackExchange.Redis;
Depois que a instalação for concluída, o cliente de cache Redis estará disponível para uso com o seu projeto.
Conectar-se ao cache
Vamos adicionar o código para conectar-se ao cache.
Selecione Program.cs no editor.
Criar um
ConnectionMultiplexer
utilizandoConnectionMultiplexer.Connect
passando sua cadeia de conexão. Nomeie o valor retornado cache.Como a conexão criada é descartável, encapsule-a em um bloco
using
. Seu código deve ter uma aparência semelhante à seguinte.string connectionString = config["CacheConnection"]; using (var cache = ConnectionMultiplexer.Connect(connectionString)) { }
Observação
A conexão com o Cache do Azure para Redis é gerenciada pela classe ConnectionMultiplexer
. Essa classe deve ser compartilhada e reutilizada em todo o seu aplicativo cliente. Nós não queremos criar uma nova conexão para cada operação. Em vez disso, queremos armazená-la como um campo em nossa classe e reutilizá-la para cada operação. Aqui, vamos usá-lo apenas no método Main, mas em uma aplicação de produção, ele deve ser armazenado em um campo de classe ou em um singleton.
Adicione um valor para o cache
Agora que temos a conexão, vamos adicionar um valor para o cache.
Dentro do bloco
using
após a conexão ter sido criada, utilize o métodoGetDatabase
para recuperar uma instância deIDatabase
:IDatabase db = cache.GetDatabase();
Chame
StringSet
no objetoIDatabase
para definir a chave "test:key" para o valor "some value".
O valor retornado de StringSet
é um bool
que indica se a chave foi adicionada.
Exiba o valor retornado de
StringSet
no console:bool setValue = db.StringSet("test:key", "some value"); Console.WriteLine($"SET: {setValue}");
Obter um valor do cache
Em seguida, recupere o valor usando
StringGet
. Esse método usa a chave para recuperar e retornar o valor.Exiba o valor retornado:
string? getValue = db.StringGet("test:key"); Console.WriteLine($"GET: {getValue}");
Seu código deve ficar assim:
using System; using Microsoft.Extensions.Configuration; using System.IO; using StackExchange.Redis; namespace SportsStatsTracker { class Program { static void Main(string[] args) { var config = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .Build(); string connectionString = config["CacheConnection"]; using (var cache = ConnectionMultiplexer.Connect(connectionString)) { IDatabase db = cache.GetDatabase(); bool setValue = db.StringSet("test:key", "some value"); Console.WriteLine($"SET: {setValue}"); string? getValue = db.StringGet("test:key"); Console.WriteLine($"GET: {getValue}"); } } } }
Execute o aplicativo para ver o resultado. Insira
dotnet run
na janela do terminal abaixo do editor. Verifique se você está na pasta do projeto, caso contrário, não encontrará seu código para compilar e executar.dotnet run
Dica
Se o programa for compilado, mas não faz o que você espera, pode ser porque você não salvou as alterações no editor. Não se esqueça de salvar as alterações ao alternar entre as janelas do terminal e do editor.
Usar as versões assíncronas dos métodos
Conseguimos obter e definir valores do cache, mas estamos usando as versões síncronas mais antigas desses métodos. Em aplicativos do lado do servidor, esses métodos não são um tipo de uso eficiente dos threads. Nesse caso, é melhor usar as versões assíncronas dos métodos. É fácil identificá-los: todos eles terminam com Async.
Para facilitar o trabalho com esses métodos, é possível utilizar o C# async
e await
palavras-chave. Se você estiver usando seu próprio ambiente de desenvolvimento do .NET Core em vez do Cloud Shell integrado, use pelo menos o C# 7.1 para poder aplicar essas palavras-chave ao método Main.
Aplicar a palavra-chave assíncrona
Para aplicar a palavra-chave async
ao método Main. Teremos que fazer duas coisas.
Adicione a palavra-chave
async
à assinatura do método Main.Alterar o tipo de retorno de
void
paraTask
.using Microsoft.Extensions.Configuration; using StackExchange.Redis; namespace SportsStatsTracker { class Program { static async Task Main(string[] args) { ...
Obter e definir valores de forma assíncrona
Podemos manter os métodos síncronos em vigor. Vamos adicionar uma chamada aos métodos StringSetAsync
e StringGetAsync
para adicionar outro valor ao cache. Defina o valor de counter como 100.
Use os métodos
StringSetAsync
eStringGetAsync
para definir e recuperar uma chave chamada counter. Defina o valor como 100.Aplicar a palavra-chave
await
para obter os resultados de cada método.Exiba os resultados na janela do console, assim como foi feito com as versões síncronas:
// Simple get and put of integral data types into the cache setValue = await db.StringSetAsync("counter", "100"); Console.WriteLine($"SET: {setValue}"); getValue = await db.StringGetAsync("counter"); Console.WriteLine($"GET: {getValue}");
Execute o aplicativo novamente. Ele ainda deve funcionar e agora tem dois valores.
Incrementar o valor
Use o método
StringIncrementAsync
para incrementar seu contador valor. Passe o número 50 para adicioná-lo ao contador:Observe que o método utiliza as chaves e tanto uma
long
oudouble
.Dependendo dos parâmetros passados, ele retorna um
long
oudouble
.
Emitir os resultados do método ao console.
long newValue = await db.StringIncrementAsync("counter", 50); Console.WriteLine($"INCR new value = {newValue}");
Outras operações
Por fim, vamos tentar executar alguns métodos adicionais com o suporte do ExecuteAsync
.
Execute PING para testar a conexão do servidor. Ele deverá responder com PONG.
Execute FLUSHDB para limpar os valores do banco de dados. Ele deverá responder com OK:
var result = await db.ExecuteAsync("ping"); Console.WriteLine($"PING = {result.Type} : {result}"); result = await db.ExecuteAsync("flushdb"); Console.WriteLine($"FLUSHDB = {result.Type} : {result}");
O código final deve ter uma aparência semelhante à seguinte:
using Microsoft.Extensions.Configuration;
using StackExchange.Redis;
namespace SportsStatsTracker
{
class Program
{
static async Task Main(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
string connectionString = config["CacheConnection"];
using (var cache = ConnectionMultiplexer.Connect(connectionString))
{
IDatabase db = cache.GetDatabase();
bool setValue = db.StringSet("test:key", "some value");
Console.WriteLine($"SET: {setValue}");
string getValue = db.StringGet("test:key");
Console.WriteLine($"GET: {getValue}");
setValue = await db.StringSetAsync("counter", "100");
Console.WriteLine($"SET: {setValue}");
getValue = await db.StringGetAsync("counter");
Console.WriteLine($"GET: {getValue}");
long newValue = await db.StringIncrementAsync("counter", 50);
Console.WriteLine($"INCR new value = {newValue}");
var result = await db.ExecuteAsync("ping");
Console.WriteLine($"PING = {result.Type} : {result}");
result = await db.ExecuteAsync("flushdb");
Console.WriteLine($"FLUSHDB = {result.Type} : {result}");
}
}
}
}
Agora, quando você executar o aplicativo, a seguinte saída será emitida:
SET: True
GET: some value
SET: True
GET: 100
INCR new value = 150
PING = SimpleString : PONG
FLUSHDB = SimpleString : OK
Desafio
Como desafio, tente serializar um tipo de objeto no cache. Aqui estão as etapas básicas.
Crie um novo
class
com algumas propriedades públicas. É possível inventar um próprio ("Person" ou "Car" são populares) ou utilizar o exemplo "GameStats" da unidade anterior.Adicionar suporte para o pacote NuGet Newtonsoft.Json utilizando
dotnet add package
.Adicionar um
using
para o namespaceNewtonsoft.Json
.Criar um de seus objetos.
Serialize com
JsonConvert.SerializeObject
e utilizeStringSetAsync
para efetuar push para o cache.Recupere-o do cache com
StringGetAsync
e, em seguida, desserialize-o comJsonConvert.DeserializeObject<T>
.
Agora que temos um Cache Redis criado no Azure, vamos criar um aplicativo para usá-lo. Verifique se você tem as informações de conexão do portal Azure.
Observação
O Cloud Shell integrado está disponível no lado direito. É possível usar o prompt de comando para criar e executar o código de exemplo que estamos criando aqui ou executar essas etapas localmente, no caso de uma configuração do ambiente de desenvolvimento do Node.js.
Criar um aplicativo de console
Usaremos um aplicativo de console simples para focarmos na implementação do Redis.
No Cloud Shell, crie um novo diretório chamado
redisapp
e inicialize um novo aplicativo Node.js nele.mkdir redisapp cd redisapp npm init -y touch app.js
Nosso aplicativo usará os seguintes pacotes npm:
- redis: o pacote JavaScript mais usado para se conectar ao Redis.
- bluebird: usado para converter os métodos do estilo de retorno de chamada no pacote
redis
em uma Promessa com espera. - dotenv: carrega variáveis de ambiente de um arquivo
.env
, em que as informações de conectividade do Redis serão armazenadas.
Vamos instalá-las agora. Execute este comando para adicioná-las ao aplicativo:
npm install redis bluebird dotenv
Adicionar configuração
Vamos adicionar as informações de conexão obtidas no portal do Azure a um arquivo de configuração .env
.
Crie um arquivo .env para o projeto:
touch .env
Abra o editor de código inserindo
code .
na pasta do projeto. Caso esteja trabalhando localmente, use o Visual Studio Code. As etapas aqui serão alinhadas principalmente ao uso.Selecione o arquivo .env no editor e cole o texto a seguir:
REDISHOSTNAME= REDISKEY= REDISPORT=
Cole o nome do host, a chave primária e a porta após o sinal de igual em cada linha respectiva. O arquivo finalizado terá aparência semelhante à do exemplo a seguir:
REDISHOSTNAME=myredishost.redis.cache.windows.net REDISKEY=K21mLSMN++z8d1FvIeMGy3VOAgoOmqaNYCqeE44eMDc= REDISPORT=6380
Salve o arquivo com Ctrl+S no Windows e no Linux ou Cmd+S no macOS.
Configurar a implementação
Agora é hora de escrever o código do aplicativo.
Selecione app.js no editor.
Primeiro, adicione as instruções
require
. Cole o seguinte código na parte superior do arquivo.var Promise = require("bluebird"); var redis = require("redis");
Depois, vamos carregar a configuração
.env
e usar a funçãopromisifyAll
do bluebird para converter as funções e os métodos do pacoteredis
em uma Promessa com espera. Cole o código a seguir:require("dotenv").config(); Promise.promisifyAll(redis);
Agora, inicializaremos um cliente Redis. Cole no código de texto clichê da unidade anterior (usando
process.env
para acessar o nome do host, a porta e a chave) para criar o cliente:const client = redis.createClient( process.env.REDISPORT, process.env.REDISHOSTNAME, { password: process.env.REDISKEY, tls: { servername: process.env.REDISHOSTNAME } } );
Usar o cliente para trabalhar com o cache
Estamos prontos para escrever código para interagir com o cache Redis.
Primeiro, vamos adicionar um wrapper de função
async
ao fim do arquivo para conter o código principal. Esse wrapper é necessário para executarawait
nas chamadas de função assíncronas que usaremos. Todo o restante do código que será adicionado nesta unidade estará nesse wrapper.(async () => { // The rest of the code you'll paste in goes here. })();
Adicione um valor ao cache com o método
setAsync
e leia-o novamente comgetAsync
:console.log("Adding value to the cache"); await client.setAsync("myKey", "myValue"); console.log("Reading value back:"); console.log(await client.getAsync("myKey"));
Envie um ping para o cache com
pingAsync
:console.log("Pinging the cache"); console.log(await client.pingAsync());
Exclua todas as chaves no cache com
flushdbAsync
:await client.flushdbAsync();
Por fim, feche a conexão com
quitAsync
:await client.quitAsync();
Salve o arquivo. O aplicativo concluído deve ter esta aparência:
var Promise = require("bluebird"); var redis = require("redis"); require("dotenv").config(); Promise.promisifyAll(redis); const client = redis.createClient( process.env.REDISPORT, process.env.REDISHOSTNAME, { password: process.env.REDISKEY, tls: { servername: process.env.REDISHOSTNAME } } ); (async () => { console.log("Adding value to the cache"); await client.setAsync("myKey", "myValue"); console.log("Reading value back:"); console.log(await client.getAsync("myKey")); console.log("Pinging the cache"); console.log(await client.pingAsync()); await client.flushdbAsync(); await client.quitAsync(); })();
Execute o aplicativo. No Cloud Shell, execute o seguinte comando.
node app.js
Você verá os seguintes resultados.
Adding value to the cache Reading value back: myValue Pinging the cache PONG