这个例子展示了使用LEADTOOLS文档库实现Azure Redis缓存。
作为一个成熟的示例,它可以在生产环境中使用。但是,它需要将大型二进制数据直接保存到缓存中。因此,如果文档要从多个服务器访问,由于重新同步时间的增加,它可能不适合。在这种情况下,请参阅Azure Redis缓存与存储Blobs示例为了更好的方法。
这个示例代码需要以下NuGet包:
在文档服务源代码中,替换其中的代码ServiceHelper。CreateCache
:
//获取Redis Cache数据库对象
var配置=“your-cache-url.redis.cache.windows.net,密码=你的密码”;
varconfigurationOptions = configurationOptions . parse(配置);
//增加同步超时时间,因为我们可能存储较大的二进制文件。
//注意RedisWithBlobsObjectCache实现不需要这个。
configurationOptions。SyncTimeout = 5000;
ConnectionMultiplexer connection = ConnectionMultiplexer. connect (configurationOptions);
IDatabase redisDatabase = connection.GetDatabase();
//创建LEADTOOLS ObjectCache包装器
_cache =新RedisObjectCache (redisDatabase);
RedisObjectCache.cs
使用Leadtools;
使用Leadtools.Caching;
使用Leadtools.Codecs;
使用Leadtools.Svg;
使用Newtonsoft.Json;
使用StackExchange.Redis;
使用系统;
使用System.Collections.Generic;
使用先;
名称空间MyNamespace
{
///<摘要>
///包装一个Redis缓存IDatabase对象,与LEADTOOLS文档库一起使用
///> < /总结
公共类RedisObjectCache: ObjectCache
{
私人RedisObjectCache() {}
///<摘要>
///从Redis缓存数据库对象初始化一个LEADTOOLS对象缓存包装器。
///> < /总结
///已完全初始化的Redis数据库对象
公共RedisObjectCache (StackExchange.Redis。IDatabase缓存)
{
这.Cache = cache;
}
///<摘要>
///正在使用的Redis缓存数据库对象。
///> < /总结
公共idatabase缓存{得到;私人集;}
// --------------------------------------------------------------------------------------
//这些成员必须由我们的类实现,并由Document工具箱调用
// --------------------------------------------------------------------------------------
公共覆盖字符串的名字
{
得到
{
返回“Redis对象缓存”;
}
}
公共覆盖CacheSerializationMode PolicySerializationMode
{
得到
{
// Redis不使用这个,所以我们假设它是二进制的
返回CacheSerializationMode.Binary;
}
集{扔新NotSupportedException(由于);}
}
公共覆盖CacheSerializationMode DataSerializationMode
{
得到
{
//二进制意味着我们将自己序列化
返回CacheSerializationMode.Binary;
}
集{扔新NotSupportedException(由于);}
}
公共覆盖DefaultCacheCapabilities DefaultCacheCapabilities
{
得到
{
//我们支持序列化:这意味着,工具箱可以给我们发送“胖”的。net对象
//我们将序列化它们而不改变原始引用
返回DefaultCacheCapabilities.Serialization;
}
}
公共覆盖CacheItem
AddOrGetExisting (CacheItem item, CacheItemPolicy policy) {
//添加缓存项时调用的方法。
//必须返回旧值
//解析密钥。记住,我们没有区域
varresolvedKey = ResolveCacheKey(项目。RegionName item.Key);
CacheItem
oldItem =零; //获取旧值(如果有的话)
如果(这.Cache.KeyExists (resolvedKey))
{
RedisValue existingValue =这.Cache.StringGet (resolvedKey);
varoldValue = getfromache
(existingValue, item. value)RegionName item.Key); oldItem =新CacheItem < T >(项目。Key, (T)oldValue, item.RegionName);
}
//添加新值
AddToCache(项目、政策);
//返回旧项目
返回oldItem;
}
公共覆盖CacheItem < T > GetCacheItem < T > (字符串键,字符串regionName)
{
//如果我们有一个带有此键的项,则返回它。否则,返回null
varresolvedKey = ResolveCacheKey(regionName, key);
CacheItem
item =零; 如果(这.Cache.KeyExists (resolvedKey))
{
RedisValue value =这.Cache.StringGet (resolvedKey);
varitemValue = getfromache
(value, regionName, key); 项=新CacheItem
(key, (T)itemValue, regionName); }
返回项;
}
公共覆盖保龄球包含(字符串键,字符串regionName)
{
//检查键是否在字典中
varresolvedKey = ResolveCacheKey(regionName, key);
var存在=这.Cache.KeyExists (resolvedKey);
返回存在;
}
公共覆盖保龄球UpdateCacheItem < T > (CacheItem < T >项)
{
//更新项目
如果(项目= =零)
扔新ArgumentNullException (“项目”);
varresolvedKey = ResolveCacheKey(项目。RegionName item.Key);
var存在=这.Cache.KeyExists (resolvedKey);
如果(存在)
{
AddToCache(项目,零);
}
返回存在;
}
公共覆盖T删除< T > (字符串键,字符串regionName)
{
//删除找到的值,返回旧值
T existingValue =默认的(T);
varresolvedKey = ResolveCacheKey(regionName, key);
如果(这.Cache.KeyExists (resolvedKey))
{
RedisValue value =这.Cache.StringGet (resolvedKey);
existingValue = (T)GetFromCache
(value, regionName, key); }
//删除
DeleteItem(关键,regionName);
返回existingValue;
}
公共覆盖无效DeleteItem (字符串键,字符串regionName)
{
//如果找到,删除
DeleteFromCache (regionName、关键);
}
公共覆盖无效UpdatePolicy (字符串key, CacheItemPolicy策略字符串regionName)
{
// Redis缓存不允许我们更新一个项目的过期策略。
}
私人静态字符串ResolveCacheKey (字符串regionName,字符串键)
{
//两个都必须是非空字符串
如果(字符串.IsNullOrEmpty (regionName))扔新InvalidOperationException (“地区名称必须是非空字符串”);
如果(字符串.IsNullOrEmpty(关键))扔新InvalidOperationException ("区域键名必须是非空字符串");
// regionName可能不是唯一的,key也可能不是唯一的,但是把它们结合起来,我们就保证了一个唯一的key
返回regionName +“-”+关键;
}
// LEADTOOLS文档库将调用我们以下项目:
// -与Redis兼容的本地类型:字符串,字节数组和JSON序列化对象。对于这些,我们只会传递
// - RasterImage或SvgDocument,这些与Redis不兼容,我们必须先序列化它们
私人无效AddToCache
(CacheItem item, CacheItemPolicy policy) {
//从项目数据中获取Redis值
字节[] blob =零;
保龄球hasBlob =假;
字符串json =零;
vartypeOfT =typeof(T);
如果(typeOfT = =typeof(RasterImage))
{
blob = ImageToBlob(项目。价值作为RasterImage);
hasBlob =真正的;
}
其他的如果(typeOfT = =typeof(SvgDocument))
{
blob = SvgToBlob(项目。价值作为SvgDocument);
hasBlob =真正的;
}
其他的如果(typeOfT = =typeof(字节[]))
{
Blob =项目。价值作为字节[];
hasBlob =真正的;
}
其他的
{
// JSON序列化
json = JsonConvert.SerializeObject(item.Value);
hasBlob =假;
}
//如果使用滑动过期,则将其设置为绝对值
时间间隔?到期=零;
如果(政策! =零)
{
varexpiryDate = policy.AbsoluteExpiration;
如果(政策。> timespan . 0)
{
expiryDate = DateTime.UtcNow.Add(policy.SlidingExpiration);
}
//现在,我们有一个日期,将其转换为从现在开始的时间跨度(所有UTC)
期满=过期日期。减去(DateTime.UtcNow);
}
varresolvedKey = ResolveCacheKey(项目。RegionName item.Key);
//设置缓存项的值
如果(hasBlob)
这.Cache。StringSet(resolvedKey, blob,到期);
其他的
这.Cache。StringSet(resolvedKey, json,到期);
}
私人对象GetFromCache < T > (RedisValue价值,字符串regionName,字符串键)
{
vartypeOfT =typeof(T);
对象结果=零;
如果(typeOfT = =typeof(光栅图像)|| typeOfT ==typeof(SvgDocument) || typeOfT ==typeof(字节[]))
{
//读取blob
字节[] blob = (字节[])值;
如果(typeOfT = =typeof(RasterImage))
{
result = ImageFromBlob(blob);
}
其他的如果(typeOfT = =typeof(SvgDocument))
{
result = SvgFromBlob(blob);
}
其他的
{
结果= (字节[])团;
}
}
其他的
{
// JSON反序列化它
result = JsonConvert.DeserializeObject
(value); }
返回结果;
}
私人无效DeleteFromCache (字符串regionName,字符串键)
{
varresolvedKey = ResolveCacheKey(regionName, key);
如果(这.Cache.KeyExists (resolvedKey))
这.Cache.KeyDelete (resolvedKey);
}
// Helper方法将RasterImage或SvgDocument对象从/转换为字节[]
私人静态字节[] ImageToBlob(RasterImage image)
{
如果(图片= =零)
返回零;
//以PNG格式保存到内存流中,使用字节[]数据
使用(varrasterCodecs =新RasterCodecs ())
{
使用(var女士=新MemoryStream ())
{
rasterCodecs。Save(image, ms, RasterImageFormat.Png, 0);
返回ms.GetBuffer ();
}
}
}
私人静态RasterImage ImageFromBlob (字节[] blob)
{
如果(blob = =零| | blob。长度== 0)
返回零;
//加载一个光栅图像,使用字节[]数据
使用(varrasterCodecs =新RasterCodecs ())
{
使用(var女士=新MemoryStream (blob))
{
返回rasterCodecs。负载(ms, 1);
}
}
}
私人静态字节[] SvgToBlob(SvgDocument svg)
{
如果(svg = =零)
返回零;
使用(var女士=新MemoryStream ())
{
svg。SaveToStream(女士,零);
返回ms.GetBuffer ();
}
}
私人静态SvgDocument SvgFromBlob (字节[] blob)
{
如果(blob = =零| | blob。长度== 0)
返回零;
返回SvgDocument。LoadFromMemory(blob, 0, blob。长度,零);
}
//
//这些成员必须被我们的类覆盖,但不会被Document工具箱调用
//抛出一个不支持的异常
//
//这是默认区域支持。我们没有
公共覆盖对象这[字符串例子)
{
得到
{
扔新NotSupportedException(由于);
}
集
{
扔新NotSupportedException(由于);
}
}
//一次性删除一个区域我们对此不支持
//注意:只有当我们有DefaultCacheCapabilities.CacheRegions时才会被调用。因为我们不这样做,所以调用者负责
//调用DeleteAll传递区域的所有项目(依次调用每个项目的DeleteItem)
公共覆盖无效DeleteRegion (字符串regionName)
{
扔新NotSupportedException(由于);
}
//开始添加外部资源我们对此不支持
//注意:只有当我们有DefaultCacheCapabilities时才会调用。ExternalResources
公共覆盖Uri BeginAddExternalResource (字符串键,字符串regionName,保龄球读写)
{
扔新NotSupportedException(由于);
}
//结束添加外部资源。我们对此不支持
//注意:只有当我们有DefaultCacheCapabilities时才会调用。ExternalResources
公共覆盖无效EndAddExternalResource < T > (保龄球提交,字符串key, T值,CacheItemPolicy策略,字符串regionName)
{
扔新NotSupportedException(由于);
}
//获取项目外部资源。我们对此不支持
//注意:只有当我们有DefaultCacheCapabilities时才会调用。ExternalResources
公共覆盖Uri GetItemExternalResource (字符串键,字符串regionName,保龄球读写)
{
扔新NotSupportedException(由于);
}
//删除项目外部资源。我们对此不支持
//注意:只有当我们有DefaultCacheCapabilities时才会调用。ExternalResources
公共覆盖无效RemoveItemExternalResource (字符串键,字符串regionName)
{
扔新NotSupportedException(由于);
}
//获取项目虚拟目录路径我们对此不支持
//注意:只有当我们有DefaultCacheCapabilities时才会调用。VirtualDirectory
公共覆盖Uri GetItemVirtualDirectoryUrl (字符串键,字符串regionName)
{
扔新NotSupportedException(由于);
}
//获取缓存中的项数。我们对此不支持
公共覆盖长GetCount (字符串regionName)
{
扔新NotSupportedException(由于);
}
/ /统计数据。我们对此不支持
公共覆盖CacheStatistics GetStatistics ()
{
扔新NotSupportedException(由于);
}
/ /统计数据。我们对此不支持
公共覆盖CacheStatistics GetStatistics (字符串键,字符串regionName)
{
扔新NotSupportedException(由于);
}
//获取所有的值。我们对此不支持
公共覆盖IDictionary <字符串,对象> getvalue (IEnumerable <字符串>键,字符串regionName)
{
扔新NotSupportedException(由于);
}
//项目的枚举。我们对此不支持
受保护的覆盖IEnumerator < KeyValuePair <字符串,对象> > GetEnumerator ()
{
扔新NotSupportedException(由于);
}
//键的枚举我们对此不支持
公共覆盖无效EnumerateKeys (字符串区域,EnumerateCacheEntriesCallback
{
扔新NotSupportedException(由于);
}
//区域的枚举。我们对此不支持
公共覆盖无效EnumerateRegions (EnumerateCacheEntriesCallback回调)
{
扔新NotSupportedException(由于);
}
}
}