IMemoryCache似乎有我习惯的那种api,你输入任何类型的对象,你得到一个可以回放到原始类型的对象.使用MemoryCache时我认为不涉及序列化,对象只是直接存储在内存中,这就是api更简单的原因.
IDistibutedCache似乎就像我们应该用来开发可扩展的云应用程序,但它有一个不太吸引人的api,因为我们传入一个字节数组并返回一个字节数组.在这种情况下,对象必须是可序列化的,我们必须自己序列化它们,以便将它们放入缓存中并在检索后反序列化它们,例如在此代码片段中:
public async Task<TreeNode<NavigationNode>> GetTree() { if (rootNode == null) { await cache.ConnectAsync(); byte[] bytes = await cache.GetAsync(cacheKey); if (bytes != null) { string json = Encoding.UTF8.GetString(bytes); rootNode = BuildTreeFromJson(json); } else { rootNode = await BuildTree(); string json = rootNode.ToJsonCompact(); await cache.SetAsync( cacheKey,Encoding.UTF8.GetBytes(json),new DistributedCacheEntryOptions().SetSlidingExpiration( TimeSpan.FromSeconds(100)) ); } } return rootNode; }
在这个具体示例中,我使用自定义序列化和反序列化,因为此示例中的对象需要一些序列化帮助,因为它不仅仅是一个简单的类.
对于具有易于序列化的对象的缓存的更一般用法,似乎我应该在IDistributedCache周围实现某种缓存助手或包装,以创建一个更类似于IMemoryCache的api,这样我就可以传入对象并通过密钥并减少我的缓存代码的复杂性和重复.在内部我想我的CacheHelper类只会使用标准的json序列化,还是我还应该使用其他东西?
在框架中是否有任何类似CacheHelper的计划,或者我应该实现自己的?
我认为特别是在像Azure这样的环境中我应该为从sqlAzure数据库中频繁检索的大多数事物实现缓存以降低成本,而IDistributeCache允许通过DI轻松插入不同的缓存解决方案Azure缓存或Redit等.
使用LocalCache时是否与直接使用MemoryCache有任何性能差异?
我们应该总是或几乎总是使用IDistributedCache,还是有特定的示例场景,首选使用IMemoryCache?
解决方法
我们可以添加一组IDistributedCache扩展方法here(它是所有开源的,所以我们可以自己修复并提交拉取请求:)).
请注意,BinaryFormatter在.NET Core中不可用(不确定它是否会出现)所以我用#if DNX451包装它,并包含两个运行时都可以使用的BinaryWriter和BinaryReader扩展方法.另请注意,如果您使用的是BinaryFormatter扩展方法,则需要将[Serializable]属性添加到要序列化的实体中.
public static class CacheExtensions { // Omitted existing extension methods... public static async Task<bool> GetBooleanAsync(this IDistributedCache cache,string key) { byte[] bytes = await cache.GetAsync(key); using (MemoryStream memoryStream = new MemoryStream(bytes)) { BinaryReader binaryReader = new BinaryReader(memoryStream); return binaryReader.ReadBoolean(); } } public static async Task<char> GetCharAsync(this IDistributedCache cache,string key) { byte[] bytes = await cache.GetAsync(key); using (MemoryStream memoryStream = new MemoryStream(bytes)) { BinaryReader binaryReader = new BinaryReader(memoryStream); return binaryReader.ReadChar(); } } public static async Task<decimal> GetDecimalAsync(this IDistributedCache cache,string key) { byte[] bytes = await cache.GetAsync(key); using (MemoryStream memoryStream = new MemoryStream(bytes)) { BinaryReader binaryReader = new BinaryReader(memoryStream); return binaryReader.ReadDecimal(); } } public static async Task<double> GetDoubleAsync(this IDistributedCache cache,string key) { byte[] bytes = await cache.GetAsync(key); using (MemoryStream memoryStream = new MemoryStream(bytes)) { BinaryReader binaryReader = new BinaryReader(memoryStream); return binaryReader.ReadDouble(); } } public static async Task<short> GetShortAsync(this IDistributedCache cache,string key) { byte[] bytes = await cache.GetAsync(key); using (MemoryStream memoryStream = new MemoryStream(bytes)) { BinaryReader binaryReader = new BinaryReader(memoryStream); return binaryReader.ReadInt16(); } } public static async Task<int> GetIntAsync(this IDistributedCache cache,string key) { byte[] bytes = await cache.GetAsync(key); using (MemoryStream memoryStream = new MemoryStream(bytes)) { BinaryReader binaryReader = new BinaryReader(memoryStream); return binaryReader.ReadInt32(); } } public static async Task<long> GetLongAsync(this IDistributedCache cache,string key) { byte[] bytes = await cache.GetAsync(key); using (MemoryStream memoryStream = new MemoryStream(bytes)) { BinaryReader binaryReader = new BinaryReader(memoryStream); return binaryReader.ReadInt64(); } } public static async Task<float> GetFloatAsync(this IDistributedCache cache,string key) { byte[] bytes = await cache.GetAsync(key); using (MemoryStream memoryStream = new MemoryStream(bytes)) { BinaryReader binaryReader = new BinaryReader(memoryStream); return binaryReader.ReadSingle(); } } public static async Task<string> GetStringAsync(this IDistributedCache cache,string key) { byte[] bytes = await cache.GetAsync(key); using (MemoryStream memoryStream = new MemoryStream(bytes)) { BinaryReader binaryReader = new BinaryReader(memoryStream); return binaryReader.ReadString(); } } public static Task SetAsync(this IDistributedCache cache,string key,bool value,DistributedCacheEntryOptions options) { byte[] bytes; using (MemoryStream memoryStream = new MemoryStream()) { BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write(value); bytes = memoryStream.ToArray(); } return cache.SetAsync(key,bytes,options); } public static Task SetAsync(this IDistributedCache cache,char value,decimal value,double value,short value,int value,long value,float value,string value,options); } #if DNX451 public static async Task<T> GetAsync<T>(this IDistributedCache cache,string key) { byte[] bytes = await cache.GetAsync(key); using (MemoryStream memoryStream = new MemoryStream(bytes)) { BinaryFormatter binaryFormatter = new BinaryFormatter(); return (T)binaryFormatter.Deserialize(memoryStream); } } public static Task SetAsync<T>(this IDistributedCache cache,T value) { return SetAsync(cache,key,value,new DistributedCacheEntryOptions()); } public static Task SetAsync<T>(this IDistributedCache cache,T value,DistributedCacheEntryOptions options) { byte[] bytes; using (MemoryStream memoryStream = new MemoryStream()) { BinaryFormatter binaryFormatter = new BinaryFormatter(); binaryFormatter.Serialize(memoryStream,value); bytes = memoryStream.ToArray(); } return cache.SetAsync(key,options); } #endif }