在ASP.NET 5中,我们有两个用于缓存IDistributedCache和IMemoryCache的接口,然后我们还有LocalCache,这是一个在内部使用MemoryCache的IDistributedCache的实现。
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?
答案 0 :(得分:4)
我在ASP.NET Caching GitHub项目上发布了this问题。
我们可以添加一组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, string key, char 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, string key, decimal 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, string key, double 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, string key, short 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, string key, int 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, string key, long 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, string key, float 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, string key, string 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);
}
#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, string key, T value)
{
return SetAsync(cache, key, value, new DistributedCacheEntryOptions());
}
public static Task SetAsync<T>(this IDistributedCache cache, string key, 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, bytes, options);
}
#endif
}
答案 1 :(得分:3)
以下是IDistributedCache的一些通用扩展,对我在.net core 2上运行有用。您可以使用它们来序列化和存储任何对象。
public static class DistributedCacheExtensions
{
public static Task SetAsync<T>(this IDistributedCache cache, string key, T value)
{
return SetAsync(cache, key, value, new DistributedCacheEntryOptions());
}
public static Task SetAsync<T>(this IDistributedCache cache, string key, T value, DistributedCacheEntryOptions options)
{
byte[] bytes;
using (var memoryStream = new MemoryStream())
{
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, value);
bytes = memoryStream.ToArray();
}
return cache.SetAsync(key, bytes, options);
}
public static async Task<T> GetAsync<T>(this IDistributedCache cache, string key)
{
var val = await cache.GetAsync(key);
var result = default(T);
if (val == null) return result;
using (var memoryStream = new MemoryStream(val))
{
var binaryFormatter = new BinaryFormatter();
result = (T)binaryFormatter.Deserialize(memoryStream);
}
return result;
}
public static bool TryGet<T>(this IDistributedCache cache, string key, out T value)
{
var val = cache.Get(key);
value = default(T);
if (val == null) return false;
using (var memoryStream = new MemoryStream(val))
{
var binaryFormatter = new BinaryFormatter();
value = (T)binaryFormatter.Deserialize(memoryStream);
}
return true;
}
}