Interagire con la cache di Azure per Redis usando .NET
Un'applicazione client usa in genere una libreria client per formare richieste ed eseguire comandi in una cache Redis. È possibile ottenere un elenco di librerie client direttamente dalla pagina dei client Redis.
Esecuzione di comandi nella cache Redis
Un client Redis ad alte prestazioni tra i più diffusi per il linguaggio .NET è StackExchange.Redis. Il pacchetto è disponibile tramite NuGet e può essere aggiunto al codice .NET tramite la riga di comando o l'ambiente di sviluppo integrato. Di seguito vengono mostrati alcuni esempi di come usare il client.
Connessione alla cache Redis con StackExchange.Redis
È importante ricordare che per la connessione a un server Redis vengono usati l'indirizzo dell'host, il numero della porta e una chiave di accesso. Azure offre anche per alcuni client Redis una stringa di connessione che unisce questi dati in una singola stringa. Avrà un aspetto simile al seguente, con i campi cache-name
e password-here
compilati con valori effettivi:
[cache-name].redis.cache.windows.net:6380,password=[password-here],ssl=True,abortConnect=False
È possibile passare questa stringa a StackExchange.Redis per creare una connessione al server.
Si noti che ala fine sono presenti due altri parametri:
- ssl: assicura che le comunicazioni siano crittografate.
- abortConnection: consente la creazione di una connessione anche se il server non è disponibile in quel momento.
Sono disponibili altri parametri facoltativi da aggiungere alla fine della stringa per configurare la libreria client.
Creazione di una connessione
L'oggetto principale della connessione in StackExchange.Redis è la classe StackExchange.Redis.ConnectionMultiplexer
. Questo oggetto astrae il processo di connessione a un server Redis o a un gruppo di server. È ottimizzato per gestire le connessioni in modo efficiente e deve essere disponibile quando è necessario accedere alla cache.
È possibile creare un'istanza di ConnectionMultiplexer
usando il metodo statico ConnectionMultiplexer.Connect
o ConnectionMultiplexer.ConnectAsync
, passando una stringa di connessione o un oggetto ConfigurationOptions
.
Ecco un semplice esempio:
using StackExchange.Redis;
...
var connectionString = "[cache-name].redis.cache.windows.net:6380,password=[password-here],ssl=True,abortConnect=False";
var redisConnection = ConnectionMultiplexer.Connect(connectionString);
Quando è disponibile un'istanza di ConnectionMultiplexer
, è necessario eseguire tre operazioni principali:
- Accedere a un database Redis.
- Usare le funzionalità editore/sottoscrittore di Redis, che non rientrano nell'ambito di questo modulo.
- Accedere a un singolo server per finalità di manutenzione o monitoraggio.
Accesso a un database Redis
Il tipo IDatabase
rappresenta il database Redis. È possibile recuperarne uno usando il metodo GetDatabase()
:
IDatabase db = redisConnection.GetDatabase();
Suggerimento
L'oggetto restituito da GetDatabase
è un oggetto leggero e non è necessario archiviarlo. È necessario mantenere attivo solo ConnectionMultiplexer
.
Quando l'oggetto IDatabase
è disponibile, è possibile eseguire metodi per interagire con la cache. Tutti i metodi hanno versioni sincrone e asincrone che restituiscono oggetti Task
per renderli compatibili con le parole chiave async
e await
.
Ecco un esempio di archiviazione di una coppia chiave/valore nella cache:
bool wasSet = db.StringSet("favorite:flavor", "i-love-rocky-road");
Il metodo StringSet
restituisce un valore bool
per indicare che il valore è stato impostato (true
) o non è stato impostato (false
). È quindi possibile recuperare il valore con il metodo StringGet
:
string value = db.StringGet("favorite:flavor");
Console.WriteLine(value); // displays: ""i-love-rocky-road""
Recupero e impostazione di valori binari
È importante ricordare che le chiavi e i valori di Redis sono indipendenti dall'aspetto binario. Gli stessi metodi possono essere usati per archiviare dati binari. Sono disponibili operatori di conversione impliciti da usare con i tipi byte[]
in modo da potere usare i dati normalmente:
byte[] key = ...;
byte[] value = ...;
db.StringSet(key, value);
byte[] key = ...;
byte[] value = db.StringGet(key);
StackExchange.Redis rappresenta le chiavi tramite il tipo RedisKey
. Questa classe include conversioni implicite verso e da string
e byte[]
, consentendo l'uso di chiavi di testo e binarie senza complicazioni. I valori sono rappresentati dal tipo RedisValue
. Analogamente a RedisKey
, sono disponibili conversioni implicite che consentono di passare string
o byte[]
.
Altre operazioni comuni
L'interfaccia IDatabase
include alcuni metodi che consentono di usare la cache Redis. Sono disponibili metodi che consentono di usare hash, elenchi, set e set ordinati.
Ecco alcuni dei più comuni che possono essere usati con le chiavi singole. Per visualizzare l'elenco completo, è possibile leggere il codice sorgente per l'interfaccia.
Metodo | Descrizione |
---|---|
CreateBatch |
Crea un gruppo di operazioni da inviare al server come singola unità, ma non necessariamente elaborate come unità. |
CreateTransaction |
Crea un gruppo di operazioni da inviare al server come singola unità ed elaborate nel server come singola unità. |
KeyDelete |
Elimina la coppia chiave/valore. |
KeyExists |
Consente di restituire un valore che indica se la chiave specificata esiste nella cache. |
KeyExpire |
Consente di impostare una scadenza TTL per una chiave. |
KeyRename |
Consente di rinominare una chiave. |
KeyTimeToLive |
Consente di restituire il valore TTL per una chiave. |
KeyType |
Consente di restituire la rappresentazione di stringa del tipo del valore archiviato nella chiave. Possono essere restituiti tipi diversi, tra cui stringa, elenco, set, zset e hash. |
Esecuzione di altri comandi
L'oggetto IDatabase
dispone dei metodi Execute
e ExecuteAsync
che possono essere usati per passare comandi testuali al server Redis. Ad esempio:
var result = db.Execute("ping");
Console.WriteLine(result.ToString()); // displays: "PONG"
I metodi Execute
e ExecuteAsync
restituiscono un oggetto RedisResult
che è un contenitore di dati che include due proprietà:
Resp2Type
che restituisce unstring
che indica il tipo del risultato:STRING
,INTEGER
e così via.IsNull
è un valore true/false che consente di rilevare quando il risultato ènull
.
È quindi possibile usare ToString()
in RedisResult
per ottenere il valore restituito effettivo.
È possibile usare Execute
per eseguire qualsiasi comando supportato, ad esempio è possibile fare in modo che tutti i client siano connessi alla cache ("CLIENT LIST"):
var result = await db.ExecuteAsync("client", "list");
Console.WriteLine($"Type = {result.Resp2Type}\r\nResult = {result}");
In questo modo vengono restituiti tutti i client connessi:
Type = BulkString
Result = id=9469 addr=16.183.122.154:54961 fd=18 name=DESKTOP-AAAAAA age=0 idle=0 flags=N db=0 sub=1 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 ow=0 owmem=0 events=r cmd=subscribe numops=5
id=9470 addr=16.183.122.155:54967 fd=13 name=DESKTOP-BBBBBB age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 ow=0 owmem=0 events=r cmd=client numops=17
Archiviazione di valori più complessi
Redis è basato su stringhe indipendenti dall'aspetto binario, ma è possibile memorizzare nella cache oggetti grafici mediante la serializzazione di tali oggetti in un formato testuale, in genere XML o JSON. Ad esempio, per le statistiche è possibile che sia presente un oggetto GameStats
con un aspetto simile al seguente:
public class GameStat
{
public string Id { get; set; }
public string Sport { get; set; }
public DateTimeOffset DatePlayed { get; set; }
public string Game { get; set; }
public IReadOnlyList<string> Teams { get; set; }
public IReadOnlyList<(string team, int score)> Results { get; set; }
public GameStat(string sport, DateTimeOffset datePlayed, string game, string[] teams, IEnumerable<(string team, int score)> results)
{
Id = Guid.NewGuid().ToString();
Sport = sport;
DatePlayed = datePlayed;
Game = game;
Teams = teams.ToList();
Results = results.ToList();
}
public override string ToString()
{
return $"{Sport} {Game} played on {DatePlayed.Date.ToShortDateString()} - " +
$"{String.Join(',', Teams)}\r\n\t" +
$"{String.Join('\t', Results.Select(r => $"{r.team } - {r.score}\r\n"))}";
}
}
È possibile usare la libreria Newtonsoft.Json per trasformare un'istanza dell'oggetto in una stringa:
var stat = new GameStat("Soccer", new DateTime(2019, 7, 16), "Local Game",
new[] { "Team 1", "Team 2" },
new[] { ("Team 1", 2), ("Team 2", 1) });
string serializedValue = Newtonsoft.Json.JsonConvert.SerializeObject(stat);
bool added = db.StringSet("event:1950-world-cup", serializedValue);
È possibile recuperarla e trasformarla di nuovo in un oggetto mediante il processo inverso:
var result = db.StringGet("event:2019-local-game");
var stat = Newtonsoft.Json.JsonConvert.DeserializeObject<GameStat>(result.ToString());
Console.WriteLine(stat.Sport); // displays "Soccer"
Pulizia della connessione
Quando la connessione non è più necessaria, è possibile Dispose
l'elemento ConnectionMultiplexer
. L'eliminazione consente di chiudere tutte le connessioni e di arrestare le comunicazioni con il server.
redisConnection.Dispose();
redisConnection = null;