ASP.NET 5中是否有缓存模式的指导

Joe*_*tte 8 serialization caching asp.net-core-mvc asp.net-core

在ASP.NET 5中,我们有两个用于缓存IDistributedCache和IMemoryCache的接口,然后我们还有LocalCache,它是IDistributedCache的一个实现,它在内部使用MemoryCache.

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;
}
Run Code Online (Sandbox Code Playgroud)

在这个具体示例中,我使用自定义序列化和反序列化,因为此示例中的对象需要一些序列化帮助,因为它不仅仅是一个简单的类.

对于具有易于序列化的对象的缓存的更一般用法,似乎我应该在IDistributedCache周围实现某种缓存助手或包装,以创建一个更类似于IMemoryCache的api,这样我就可以传入对象并通过密钥并减少我的缓存代码的复杂性和重复.在内部,我想我的CacheHelper类只会使用标准的json序列化,还是我应该使用其他东西?

在框架中是否有任何关于此类CacheHelper的计划,还是应该实现自己的?

我认为特别是在像Azure这样的环境中我应该为从SqlAzure数据库中经常检索的大多数事物实现缓存以降低成本,而IDistributeCache允许通过DI轻松插入不同的缓存解决方案Azure缓存或Redit等.

这是正确的方法还是有更好的方法或模式的指导?

使用LocalCache时是否与直接使用MemoryCache有任何性能差异?

我们应该总是或几乎总是使用IDistributedCache,还是有特定的示例场景,首选使用IMemoryCache?

dze*_*zed 5

以下是 IDistributedCache 的一些通用扩展,它们对我在 .net core 3.1 上运行很有用。您可以使用它们来序列化和存储任何对象。

 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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Muh*_*eed 4

我在 ASP.NET Caching GitHub 项目上发布了这个问题。

这里已经有一组 IDistributedCache 扩展方法,我们可以添加它们(它都是开源的,所以我们可以自己修复这个问题并提交拉取请求:))。

请注意,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
}
Run Code Online (Sandbox Code Playgroud)