Exercice - Connecter une application au cache

Effectué

Maintenant que notre cache Redis est créé dans Azure, créons une application pour l’utiliser. Vérifiez que vous disposez des informations de votre chaîne de connexion à partir du portail Azure.

Notes

Le Cloud Shell intégré est disponible sur la droite. Vous pouvez utiliser cette invite de commandes pour créer et exécuter l’exemple de code que nous créons ici, ou pour effectuer ces étapes localement si vous utilisez une configuration d’environnement de développement .NET Core.

Création d’une application console

Nous allons utiliser une application console afin de pouvoir nous concentrer sur l’implémentation de Redis.

  1. Dans Cloud Shell, créez une application de console .NET Core, puis nommez-la SportsStatsTracker.

    dotnet new console --name SportsStatsTracker
    
  2. Quittez le répertoire actuel pour accéder au dossier pour le nouveau projet.

    cd SportsStatsTracker
    

Ajouter la chaîne de connexion

Nous allons ajouter dans le code la chaîne de connexion obtenue à partir du portail Azure. Ne stockez jamais des informations d’identification ainsi dans votre code source. Pour simplifier cet exemple, nous allons utiliser un fichier de configuration. Une meilleure approche pour une application côté serveur dans Azure consisterait à utiliser Azure Key Vault avec des certificats.

  1. Créez un fichier appsettings.json à ajouter au projet.

    touch appsettings.json
    
  2. Ouvrez l’éditeur de code en entrant code . dans le dossier du projet. Si vous travaillez localement, nous vous recommandons d’utiliser Visual Studio Code. Les étapes décrites ici sont principalement en phase avec son utilisation.

  3. Sélectionnez le fichier appsettings.json dans l’éditeur, puis ajoutez le texte suivant. Collez votre chaîne de connexion dans la valeur du paramètre.

    {
      "CacheConnection": "[value-goes-here]"
    }
    
  4. Enregistrez les modifications.

    Important

    Chaque fois que vous collez ou changez du code dans un fichier au sein de l’éditeur, veillez à l’enregistrer ensuite en utilisant le menu ..., ou des touches d’accès rapide (Ctrl+S sur Windows et Linux, Cmd+S sur macOS).

  5. Sélectionnez le fichier SportsStatsTracker.csproj dans l’éditeur pour l’ouvrir.

  6. Ajoutez le bloc de configuration <ItemGroup> suivant dans l’élément <Project> racine sous l’élément <PropertyGroup>. Cette configuration va inclure le nouveau fichier dans le projet et le copier dans le dossier de sortie. Les instructions de ce bloc vont faire en sorte que le fichier de configuration d’application soit placé dans le répertoire de sortie quand l’application est compilée/générée.

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
          ...
      </PropertyGroup>
    
      <ItemGroup>
         <None Update="appsettings.json">
           <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
         </None>
      </ItemGroup>
    
    </Project>
    
  7. Enregistrez le fichier.

    Important

    Si vous n’enregistrez pas le fichier, vous perdrez les changements apportés quand vous ajouterez le package plus tard.

Ajouter la prise en charge pour lire un fichier de configuration JSON

Une application .NET Core nécessite d’autres packages NuGet supplémentaires pour lire un fichier de configuration JSON.

Dans la section de l’invite de commandes de la fenêtre, ajoutez une référence au package NuGet Microsoft.Extensions.Configuration.Json :

dotnet add package Microsoft.Extensions.Configuration.Json

Ajouter du code pour lire le fichier de configuration

Maintenant que nous avons ajouté les bibliothèques nécessaires pour permettre la lecture de la configuration, nous devons activer cette fonctionnalité dans notre application console.

  1. Sélectionnez Program.cs dans l’éditeur. Remplacez le contenu du fichier par le code suivant :

    using Microsoft.Extensions.Configuration;
    
    namespace SportsStatsTracker
    {
        class Program
        {
            static void Main(string[] args)
            {
                var config = new ConfigurationBuilder()
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile("appsettings.json")
                    .Build();
            }
        }
    }
    

    L’instruction using nous permet d’accéder aux bibliothèques pour lire la configuration, et le code de la Main méthode initialise le système de configuration pour lire dans le fichier appsettings.json.

Obtenir la chaîne de connexion à partir de la configuration

Dans Program.cs, à la fin de la méthode Main, utilisez la nouvelle variable config pour récupérer la chaîne de connexion et la stocker dans une nouvelle variable nommée connectionString.

La variable config possède un indexeur où vous pouvez transmettre une chaîne à récupérer depuis votre fichier appSettings.json.

string connectionString = config["CacheConnection"];

Ajouter la prise en charge pour le client .NET du cache Redis

Ensuite, nous allons configurer l’application console pour utiliser le client StackExchange.Redis pour .NET.

  1. Ajoutez le package NuGet StackExchange.Redis au projet à l’aide de l’invite de commandes en bas de l’éditeur de Cloud Shell.

    dotnet add package StackExchange.Redis
    
  2. Sélectionnez Program.cs dans l’éditeur, puis ajoutez un using pour l’espace de noms StackExchange.Redis

    using StackExchange.Redis;
    

Une fois l’installation effectuée, le client du Cache Redis est prêt à être utilisé avec votre projet.

Se connecter au cache

Nous allons ajouter le code pour nous connecter au cache.

  1. Sélectionnez Program.cs dans l’éditeur.

  2. Créez un ConnectionMultiplexer à l’aide de ConnectionMultiplexer.Connect en lui passant votre chaîne de connexion. Nommez la valeur retournée cache.

  3. Dans la mesure où la connexion créée est jetable, wrappez-la dans un bloc using. Votre code doit ressembler à ce qui suit.

    string connectionString = config["CacheConnection"];
    
    using (var cache = ConnectionMultiplexer.Connect(connectionString))
    {
    
    }
    

Notes

La connexion à Azure Cache pour Redis est gérée par la classe ConnectionMultiplexer. Cette classe doit être partagée et réutilisée dans votre application cliente. Nous ne souhaitons pas créer une connexion pour chaque opération. Au lieu de cela, nous voulons la stocker comme un champ dans notre classe et la réutiliser pour chaque opération. Ici, nous allons seulement l’utiliser dans la méthode Main, mais dans une application de production, elle doit être stockée dans un champ de classe ou un singleton.

Ajouter une valeur dans le cache

Maintenant que nous avons la connexion, nous allons ajouter une valeur dans le cache.

  1. Dans le bloc using, une fois la connexion créée, utilisez la méthode GetDatabase pour récupérer une instance de IDatabase :

     IDatabase db = cache.GetDatabase();
    
  2. Appelez StringSet sur l’objet IDatabase pour définir la clé « test:key » sur la valeur « some value ».

La valeur de retour de StringSet est un bool qui indique si la clé a été ajoutée.

  1. Affichez la valeur renvoyée à partir de StringSet dans la console :

     bool setValue = db.StringSet("test:key", "some value");
     Console.WriteLine($"SET: {setValue}");
    

Obtenir une valeur à partir du cache

  1. Ensuite, récupérez la valeur en utilisant StringGet. Cette méthode prend la clé à récupérer et retourne la valeur.

  2. Affichez la sortie de la valeur renvoyée :

     string? getValue = db.StringGet("test:key");
     Console.WriteLine($"GET: {getValue}");
    
  3. Votre code doit ressembler à ceci :

     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}");
                 }
             }
         }
     }
    
  4. Exécutez l’application pour voir le résultat. Entrez dotnet run dans la fenêtre de terminal sous l’éditeur. Vérifiez que vous êtes dans le dossier de projet, sinon il ne trouvera pas le code à générer et à exécuter.

     dotnet run
    

Conseil

Si le programme ne fait pas ce que vous attendez, mais qu’il se compile, cela peut être dû au fait que vous n’avez pas enregistré les changements dans l’éditeur. Pensez toujours à enregistrer les changements quand vous passez de la fenêtre du terminal à celle de l’éditeur, et inversement.

Utiliser les versions asynchrones des méthodes

Nous avons pu obtenir et définir des valeurs à partir du cache, mais nous utilisons les anciennes versions synchrones. Dans les applications côté serveur, ces méthodes n’utilisent pas efficacement nos threads. À la place, nous voulons utiliser les versions asynchrones. Vous pouvez facilement les identifier, car elles finissent toutes par Async.

Pour rendre ces méthodes faciles à utiliser, nous pouvons utiliser les mots clés async et await de C#. Si vous utilisez votre propre environnement de développement .NET Core au lieu du Cloud Shell intégré, vous devez utiliser au moins C# 7.1 pour pouvoir appliquer ces mots clés à la méthode Main.

Appliquer le mot clé async

Pour appliquer le mot clé async à la méthode Main, nous devrons faire deux choses.

  1. Ajoutez le mot clé async à la signature de la méthode Main.

  2. Passez le type de retour de void à Task.

    using Microsoft.Extensions.Configuration;
    using StackExchange.Redis;
    
    namespace SportsStatsTracker
    {
       class Program
       {
          static async Task Main(string[] args)
          {
             ...
    

Obtenir et définir des valeurs de façon asynchrone

Nous pouvons laisser les méthodes synchrones en place. Ajoutons un appel aux méthodes StringSetAsync et StringGetAsync pour ajouter une autre valeur au cache. Affectez à counter la valeur 100.

  1. Utilisez les méthodes StringSetAsync et StringGetAsync pour définir et récupérer une clé nommée counter. Affectez la valeur 100.

  2. Appliquez le mot clé await pour obtenir les résultats à partir de chaque méthode.

  3. Affichez la sortie des résultats dans la fenêtre de console, comme vous le faisiez avec les versions synchrones :

    // 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}");
    
  4. Exécutez de nouveau l'application. Elle doit toujours fonctionner, et comporter à présent deux valeurs.

Incrémenter la valeur

  1. Utilisez la méthode StringIncrementAsync pour incrémenter votre valeur de compteur. Passez le numéro 50 à ajouter au compteur :

    • Notez que la méthode prend la clé et soit un long ou double.

    • Selon les paramètres passés, elle retourne un long ou double.

  2. Sortez les résultats de la méthode sur la console.

    long newValue = await db.StringIncrementAsync("counter", 50);
    Console.WriteLine($"INCR new value = {newValue}");
    

Autres opérations

Enfin, essayons d’exécuter quelques méthodes supplémentaires avec la prise en charge de ExecuteAsync.

  1. Exécutez PING pour tester la connexion au serveur. La réponse doit être PONG.

  2. Exécutez FLUSHDB pour effacer les valeurs de la base de données. La réponse doit être OK :

    var result = await db.ExecuteAsync("ping");
    Console.WriteLine($"PING = {result.Type} : {result}");
    
    result = await db.ExecuteAsync("flushdb");
    Console.WriteLine($"FLUSHDB = {result.Type} : {result}");
    

Le code final doit ressembler à ce qui suit :

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}");
         }
      }
   }
}

Quand vous réexécutez l’application, vous devez voir la sortie suivante :

SET: True
GET: some value
SET: True
GET: 100
INCR new value = 150
PING = SimpleString : PONG
FLUSHDB = SimpleString : OK

Défi

Comme défi, essayez de sérialiser un type d’objet dans le cache. Voici les étapes de base.

  1. Créez un nouveau class avec des propriétés publiques. Vous pouvez les inventer vous-même (« Personne » ou « Voiture » sont les plus courantes), ou utiliser l’exemple « GameStats » indiqué dans l’unité précédente.

  2. Ajoutez la prise en charge du package NuGet Newtonsoft.Json en utilisant dotnet add package.

  3. Ajoutez un using pour l’espace de noms Newtonsoft.Json.

  4. Créez l’un de vos objets.

  5. Sérialisez-le avec JsonConvert.SerializeObject et utilisez StringSetAsync pour l’envoyer dans le cache.

  6. Récupérez-le auprès du cache avec StringGetAsync, puis désérialisez-le avec JsonConvert.DeserializeObject<T>.

Maintenant que notre cache Redis est créé dans Azure, créons une application pour l’utiliser. Veillez à disposer de vos informations de connexion pour le portail Azure.

Notes

Le Cloud Shell intégré est disponible sur la droite. Vous pouvez utiliser cette invite de commandes pour créer et exécuter l’exemple de code que nous créons ici, ou pour effectuer ces étapes localement si vous utilisez une configuration d’environnement de développement Node.js.

Créer une application console

Nous allons utiliser une application console afin de pouvoir nous concentrer sur l’implémentation de Redis.

  1. Dans Cloud Shell, créez un répertoire appelé redisapp. Dans ce dernier, initialisez une nouvelle application Node.js.

     mkdir redisapp
     cd redisapp
     npm init -y
     touch app.js
    
  2. Notre application va utiliser les packages npm suivants :

    • redis : Package JavaScript le plus couramment utilisé pour la connexion à Redis.
    • bluebird : Utilisé pour convertir les méthodes de style rappel du package redis en promesses avec attente possible.
    • dotenv : Charge des variables d’environnement à partir d’un fichier .env, où nous stockerons nos informations de connectivité Redis.

    Installons-les maintenant. Exécutez cette commande pour les ajouter à notre application :

    npm install redis bluebird dotenv
    

Ajouter une configuration

Ajoutons les informations de connexion obtenues du portail Azure dans un fichier de configuration .env.

  1. Créez un fichier .env dans le projet :

    touch .env
    
  2. Ouvrez l’éditeur de code en entrant code . dans le dossier du projet. Si vous travaillez localement, nous vous recommandons d’utiliser Visual Studio Code. Les étapes décrites ici sont principalement en phase avec son utilisation.

  3. Sélectionnez le fichier .env dans l’éditeur, puis collez le texte suivant :

    REDISHOSTNAME=
    REDISKEY=
    REDISPORT=
    
  4. Collez le nom d’hôte, la clé principale et le port après le signe égal sur chaque ligne respective. Le fichier complet sera similaire à l’exemple suivant :

    REDISHOSTNAME=myredishost.redis.cache.windows.net
    REDISKEY=K21mLSMN++z8d1FvIeMGy3VOAgoOmqaNYCqeE44eMDc=
    REDISPORT=6380
    
  5. Enregistrez le fichier avec Ctrl+S sur Windows et Linux, ou avec Cmd+S sur macOS.

Configurer l’implémentation

Il est temps à présent d’écrire le code de notre application.

  1. Sélectionnez app.js dans l’éditeur.

  2. Tout d’abord, nous allons ajouter nos instructions require. Collez le code suivant au début du fichier.

    var Promise = require("bluebird");
    var redis = require("redis");
    
  3. Ensuite, nous allons charger notre configuration .env et utiliser la fonction promisifyAll de bluebird pour convertir les fonctions et les méthodes du package redis en promesses avec attente possible. Collez le code suivant :

    require("dotenv").config();
    Promise.promisifyAll(redis);
    
  4. Nous allons à présent initialiser un client Redis. Collez le code réutilisable de l’unité précédente (en utilisant process.env pour accéder à notre nom d’hôte, port et clé) pour créer le client :

    const client = redis.createClient(
       process.env.REDISPORT,
       process.env.REDISHOSTNAME,
       {
          password: process.env.REDISKEY,
          tls: { servername: process.env.REDISHOSTNAME }
       }
    );
    

Utiliser le client pour travailler avec le cache

Nous sommes prêts à écrire le code pour interagir avec notre cache Redis.

  1. Tout d’abord, nous allons ajouter un wrapper de fonction async en bas du fichier pour contenir notre code principal. Nous en avons besoin pour pouvoir être en await des appels de fonctions asynchrones que nous allons utiliser. Tout le reste du code que nous allons ajouter dans cette unité sera dans ce wrapper.

    (async () => {
    
       // The rest of the code you'll paste in goes here.
    
    })();
    
  2. Ajoutez une valeur au cache avec la méthode setAsync et lisez-la de nouveau avec getAsync :

    console.log("Adding value to the cache");
    await client.setAsync("myKey", "myValue");
    
    console.log("Reading value back:");
    console.log(await client.getAsync("myKey"));
    
  3. Envoyez une commande ping au cache avec pingAsync :

    console.log("Pinging the cache");
    console.log(await client.pingAsync());
    
  4. Supprimez toutes les clés du cache avec flushdbAsync :

    await client.flushdbAsync();
    
  5. Enfin, fermez la connexion avec quitAsync :

    await client.quitAsync();
    
  6. Enregistrez le fichier. Votre application terminée doit se présenter comme suit :

    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();
    })();
    
  7. Exécutez l'application. Dans Cloud Shell, exécutez la commande suivante.

    node app.js
    

    Vous allez voir les résultats suivants.

    Adding value to the cache
    Reading value back:
    myValue
    Pinging the cache
    PONG