细心的你可能已经发现了,上面的这段代码和之前演示的 SqlServerCache 完全一致,是的,仅仅是修改一下注册的方法,我们就能在项目中进行无缝的切换;但是,对于缓存有强依赖的业务,建议还是需要做好缓存迁移,确保项目能够平滑过渡
唯一不同的是,使用 Redis 分布式缓存允许你在异步方法中调用同步获取缓存的方法,这不会导致缓存清理的问题,因为缓存的管理已经完全交给了 Redis 客户端 StackExchange.Redis 了
3. 实现自定义的分布式缓存客户端,下面的代码表示实现一个 CSRedis 客户端的分布式缓存注册扩展
3.1 定义 CSRedisCache 实现 IDistributedCache 接口
public class CSRedisCache : IDistributedCache, IDisposable
{
private CSRedis.CSRedisClient client;
private CSRedisClientOptions _options;
public CSRedisCache(IOptions<CSRedisClientOptions> optionsAccessor)
{
if (optionsAccessor == null)
{
throw new ArgumentNullException(nameof(optionsAccessor));
}
_options = optionsAccessor.Value;
if (_options.NodeRule != null && _options.ConnectionStrings != null)
client = new CSRedis.CSRedisClient(_options.NodeRule, _options.ConnectionStrings);
else if (_options.ConnectionString != null)
client = new CSRedis.CSRedisClient(_options.ConnectionString);
else
throw new ArgumentNullException(nameof(_options.ConnectionString));
RedisHelper.Initialization(client);
}
public void Dispose()
{
if (client != null)
client.Dispose();
}
public byte[] Get(string key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
return RedisHelper.Get<byte[]>(key);
}
public async Task<byte[]> GetAsync(string key, CancellationToken token = default(CancellationToken))
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
token.ThrowIfCancellationRequested();
return await RedisHelper.GetAsync<byte[]>(key);
}
public void Refresh(string key)
{
throw new NotImplementedException();
}
public Task RefreshAsync(string key, CancellationToken token = default(CancellationToken))
{
throw new NotImplementedException();
}
public void Remove(string key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
RedisHelper.Del(key);
}
public async Task RemoveAsync(string key, CancellationToken token = default(CancellationToken))
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
await RedisHelper.DelAsync(key);
}
public void Set(string key, byte[] value, DistributedCacheEntryOptions options)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
RedisHelper.Set(key, value);
}
public async Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = default(CancellationToken))
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
await RedisHelper.SetAsync(key, value);
}
}
代码不多,都是实现 IDistributedCache 接口,然后在 IDisposable.Dispose 中释放资源
3.2 自定义一个配置类 CSRedisClientOptions
public class CSRedisClientOptions
{
public string ConnectionString { get; set; }
public Func<string, string> NodeRule { get; set; }
public string[] ConnectionStrings { get; set; }
}
该配置类主要是为 CSRedis 客户端接收配置使用
3.3 注册扩展方法 CSRedisCacheServiceCollectionExtensions
public static class CSRedisCacheServiceCollectionExtensions
{
public static IServiceCollection AddCSRedisCache(this IServiceCollection services, Action<CSRedisClientOptions> setupAction)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (setupAction == null)
{
throw new ArgumentNullException(nameof(setupAction));
}
services.AddOptions();
services.Configure(setupAction);
services.Add(ServiceDescriptor.Singleton<IDistributedCache, CSRedisCache>());
return services;
}
}
自定义一个扩展方法,进行配置初始化工作,简化实际注册使用时的处理步骤
3.4 在 Startup.cs 中使用扩展
public void ConfigureServices(IServiceCollection services)
{
services.AddCSRedisCache(options =>
{
options.ConnectionString = this.Configuration["RedisConnectionString"];
});
...
}
上面的代码就简单实现了一个第三方分布式缓存客户端的注册和使用
3.5 测试自定义分布式缓存客户端,创建一个测试控制器 CustomerController
[Route("api/Customer")]
[ApiController]
public class CustomerController : Controller
{
private IDistributedCache cache;
public CustomerController(IDistributedCache cache)
{
this.cache = cache;
}
[HttpGet("NewId")]
public async Task<ActionResult<string>> NewId()
{
var id = Guid.NewGuid().ToString("N");
await this.cache.SetStringAsync("CustomerId", id);
return id;
}
[HttpGet("GetId")]
public async Task<ActionResult<string>> GetId()
{
var id = await this.cache.GetStringAsync("CustomerId");
return id;
}
}
该控制器简单实现两个接口,NewId/GetId,运行程序,输出结果正常
调用 NewId 接口创建一条缓存记录
调用 GetId 接口获取缓存记录
至此,我们完整的实现了一个自定义分布式缓存客户端注册
4. 关于本示例的使用说明
4.1 首先看一下解决方案结构
该解决方案红框处定义了 3 个不同的 Startup.cs 文件,分别是
CSRedisStartup (自定义缓存测试启动文件)
Sql_Startup (SqlServer 测试启动文件)
StackChangeRedis_Startup(StackChange.Redis 测试启动文件)