在上述代码中,我们使用了自定义类RedisCacheOptions作为Redis的配置信息类,为了实现基于POCO的配置定义,我们还继承了IOptions接口,该类的定义如下:
public class RedisCacheOptions : IOptions<RedisCacheOptions> { public string Configuration { get; set; } public string InstanceName { get; set; } RedisCacheOptions IOptions<RedisCacheOptions>.Options { get { return this; } } RedisCacheOptions IOptions<RedisCacheOptions>.GetNamedOptions(string name) { return this; } }
第三部,定义委托调用时使用的缓存上下文类CacheContext,具体代码如下:
using Microsoft.Framework.Cache.Distributed; using System; using System.IO; namespace Microsoft.Framework.Caching.Redis { internal class CacheContext : ICacheContext { private readonly MemoryStream _data = new MemoryStream(); internal CacheContext(string key) { Key = key; CreationTime = DateTimeOffset.UtcNow; } /// <summary> /// The key identifying this entry. /// </summary> public string Key { get; internal set; } /// <summary> /// The state passed into Set. This can be used to avoid closures. /// </summary> public object State { get; internal set; } public Stream Data { get { return _data; } } internal DateTimeOffset CreationTime { get; set; } // 可以让委托设置创建时间 internal DateTimeOffset? AbsoluteExpiration { get; private set; } internal TimeSpan? SlidingExpiration { get; private set; } public void SetAbsoluteExpiration(TimeSpan relative) // 可以让委托设置相对过期时间 { if (relative <= TimeSpan.Zero) { throw new ArgumentOutOfRangeException("relative", relative, "The relative expiration value must be positive."); } AbsoluteExpiration = CreationTime + relative; } public void SetAbsoluteExpiration(DateTimeOffset absolute) // 可以让委托设置绝对过期时间 { if (absolute <= CreationTime) { throw new ArgumentOutOfRangeException("absolute", absolute, "The absolute expiration value must be in the future."); } AbsoluteExpiration = absolute.ToUniversalTime(); } public void SetSlidingExpiration(TimeSpan offset) // 可以让委托设置offset过期时间 { if (offset <= TimeSpan.Zero) { throw new ArgumentOutOfRangeException("offset", offset, "The sliding expiration value must be positive."); } SlidingExpiration = offset; } internal long? GetExpirationInSeconds() { if (AbsoluteExpiration.HasValue && SlidingExpiration.HasValue) { return (long)Math.Min((AbsoluteExpiration.Value - CreationTime).TotalSeconds, SlidingExpiration.Value.TotalSeconds); } else if (AbsoluteExpiration.HasValue) { return (long)(AbsoluteExpiration.Value - CreationTime).TotalSeconds; } else if (SlidingExpiration.HasValue) { return (long)SlidingExpiration.Value.TotalSeconds; } return null; } internal byte[] GetBytes() { return _data.ToArray(); } } }
最后一步定义,RedisCache中需要的根据key键获取缓存值的快捷方法,代码如下:
using StackExchange.Redis; using System; namespace Microsoft.Framework.Caching.Redis { internal static class RedisExtensions { private const string HmGetScript = (@"return redis.call('HMGET', KEYS[1], unpack(ARGV))"); internal static RedisValue[] HashMemberGet(this IDatabase cache, string key, params string[] members) { var redisMembers = new RedisValue[members.Length]; for (int i = 0; i < members.Length; i++) { redisMembers[i] = (RedisValue)members[i]; } var result = cache.ScriptEvaluate(HmGetScript, new RedisKey[] { key }, redisMembers); // TODO: Error checking? return (RedisValue[])result; } } }
至此,所有的工作就完成了,将该缓存实现注册为Session的provider的代码方法如下:
app.UseDistributedSession(new RedisCache(new RedisCacheOptions() { Configuration = "此处填写 redis的地址", InstanceName = "此处填写自定义实例名" }), options => { options.CookieHttpOnly = true; });
关于Caching
默认情况下,本地缓存使用的是IMemoryCache接口的示例,可以通过获取该接口的示例来对本地缓存进行操作,示例代码如下:
var cache = app.ApplicationServices.GetRequiredService<IMemoryCache>(); var obj1 = cache.Get("key1"); bool obj2 = cache.Get<bool>("key2");
对于,分布式缓存,由于AddCaching,默认将IMemoryCache实例作为分布式缓存的provider了,代码如下: