使用 .NET 与 Azure Cache for Redis 交互
客户端应用程序通常使用客户端库来构建请求以及针对 Redis 缓存执行命令。 可以直接从 Redis 客户端页获取客户端库列表。
针对 Redis 缓存执行命令
用于 .NET 语言的常用高性能 Redis 客户端是 StackExchange.Redis。 可通过 NuGet 获取该包,可使用命令行或 IDE 将其添加到 .NET 代码。 下面是如何使用客户端的示例。
使用 StackExchange.Redis 连接到 Redis 缓存
回顾前面的课程,我们曾经使用主机地址、端口号和访问密钥连接到 Redis 服务器。 Azure 还为某些 Redis 客户端提供连接字符串,将这些数据一起捆绑成单个字符串。 如下所示(cache-name
和 password-here
字段中应填写实际值):
[cache-name].redis.cache.windows.net:6380,password=[password-here],ssl=True,abortConnect=False
可将此字符串传递到 StackExchange.Redis,以便与服务器建立连接。
请注意末尾有两个附加参数:
- ssl - 确保通信加密。
- abortConnection - 即使服务器当时不可用,也能创建连接。
可在该字符串的后面追加其他几个可选参数,以配置客户端库。
创建连接
StackExchange.Redis 中的主连接对象是 StackExchange.Redis.ConnectionMultiplexer
类。 此对象将连接到 Redis 服务器(或服务器组)的过程抽象化。 此对象经过优化,可以有效管理连接,每当访问缓存时,都需要准备好它。
使用静态 ConnectionMultiplexer.Connect
或 ConnectionMultiplexer.ConnectAsync
方法并传入连接字符串或 ConfigurationOptions
对象来创建 ConnectionMultiplexer
实例。
下面是一个简单示例:
using StackExchange.Redis;
...
var connectionString = "[cache-name].redis.cache.windows.net:6380,password=[password-here],ssl=True,abortConnect=False";
var redisConnection = ConnectionMultiplexer.Connect(connectionString);
创建 ConnectionMultiplexer
后,需要执行三项主要操作:
- 访问 Redis 数据库。
- 利用 Redis 的发布者/订阅者功能(不在本模块范围内)。
- 访问单个服务器以进行维护或监视。
访问 Redis 数据库
类型“IDatabase
”表示 Redis 数据库。 可以使用 GetDatabase()
方法检索 Redis 数据库:
IDatabase db = redisConnection.GetDatabase();
提示
从 GetDatabase
返回的对象是一个轻型对象,不需要存储它。 只需将 ConnectionMultiplexer
保持活动状态。
获取 IDatabase
对象后,可以执行与缓存交互的方法。 所有方法都提供同步和异步版本,这些版本返回 Task
对象,因此与 async
和 await
关键字兼容。
下面是在缓存中存储键/值的示例:
bool wasSet = db.StringSet("favorite:flavor", "i-love-rocky-road");
StringSet
方法返回 bool
,指示是已设置 (true
) 还是未设置 (false
) 该值。 然后,可以使用 StringGet
方法检索该值:
string value = db.StringGet("favorite:flavor");
Console.WriteLine(value); // displays: ""i-love-rocky-road""
获取和设置二进制值
回顾前面的课程,Redis 键和值是二进制安全的。 可以使用相同的方法存储二进制数据。 可以使用隐式转换运算符来处理 byte[]
类型,以便可以像平时一样处理数据:
byte[] key = ...;
byte[] value = ...;
db.StringSet(key, value);
byte[] key = ...;
byte[] value = db.StringGet(key);
StackExchange.Redis 使用 RedisKey
类型表示键。 此类提供与 string
和 byte[]
的相互隐藏转换,使我们能够十分轻松地使用文本和二进制键。 值由 RedisValue
类型表示。 与 RedisKey
一样,可以通过隐式转换来传递 string
或 byte[]
。
其他常见操作
IDatabase
接口包含其他几个方法用于处理 Redis 缓存。 还有一些方法可以处理哈希、列表、集和有序集。
下面是用于处理单个键的其他一些常见方法。若要查看完整列表,可以阅读该接口的源代码。
方法 | 说明 |
---|---|
CreateBatch |
创建要作为单个单元发送到服务器、但不一定要作为单个单元进行处理的一组操作。 |
CreateTransaction |
创建要作为单个单元发送到服务器、并在服务器上作为单个单元进行处理的一组操作。 |
KeyDelete |
删除键/值。 |
KeyExists |
返回给定的键是否在缓存中存在的结果。 |
KeyExpire |
针对某个键设置生存时间 (TTL) 过期时间。 |
KeyRename |
重命名某个键。 |
KeyTimeToLive |
返回键的 TTL。 |
KeyType |
返回键中存储的值类型的字符串表示形式。 可返回的不同类型包括:字符串、列表、集、zset 和哈希。 |
执行其他命令
IDatabase
对象包含可用于将文本命令传递给 Redis 服务器的 Execute
和 ExecuteAsync
方法。 例如:
var result = db.Execute("ping");
Console.WriteLine(result.ToString()); // displays: "PONG"
Execute
和 ExecuteAsync
方法返回 RedisResult
对象,该对象是包含以下两个属性的数据保存器:
Resp2Type
会返回string
,指示结果类型(“STRING
”、“INTEGER
”等)。IsNull
:结果为null
时要检测的 true/false 值。
然后,可对 RedisResult
使用 ToString()
来获取实际返回值。
可以使用 Execute
执行任何支持的命令 - 例如,可以获取已连接到缓存的所有客户端(“CLIENT LIST”):
var result = await db.ExecuteAsync("client", "list");
Console.WriteLine($"Type = {result.Resp2Type}\r\nResult = {result}");
这将输出所有连接的客户端:
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
存储更复杂的值
Redis 面向二进制安全的字符串,但你可以通过将对象图形序列化为文本格式(通常是 XML 或 JSON)来缓存这些图形。 例如,对于统计信息,我们也许可以创建如下所示的 GameStats
对象:
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"))}";
}
}
可以使用 Newtonsoft.Json 库将此对象的实例转换为字符串:
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);
可以检索该字符串,然后使用相反的过程将它还原为对象:
var result = db.StringGet("event:2019-local-game");
var stat = Newtonsoft.Json.JsonConvert.DeserializeObject<GameStat>(result.ToString());
Console.WriteLine(stat.Sport); // displays "Soccer"
清理连接
不再需要连接时,可以Dispose
ConnectionMultiplexer
。 这会关闭所有连接,并关闭与服务器的通信。
redisConnection.Dispose();
redisConnection = null;