HowTo - RedisCacheService Support

refs:

http://www.layercake-generator.net/Documentation/Pages/HowTo%20-%20RedisCacheService%20Support.html


HowTo - RedisCacheService Support

By default CacheServiceHelper.Current singleton uses LocalMemoryCacheService implementation.

This HowTo explains how to use a Redis implementation (at server-side through configuration file) instead of LocalMemoryCacheService one.

Redis is a data structure server. It is open-source, networked, in-memory, and stores keys with optional durability. According to the monthly ranking by DB-Engines.com, Redis is the most popular key-value database. The name Redis means REmote DIctionary Server -- Wikipedia

This documentation is based on StackExchange.Redis.Extensions.

1. Externals.RedisCache Library

First add a new Class Library project to the solution (choose the name you wish)

Then add a reference to the System.Extensions project

2. NuGet Packages

Open Tools > NuGet Package Manager > Package Manager Console and select the project

Install Redis 64bits (currently v2.8.19)

PM> Install-Package Redis-64

Install the StackExchange.Redis.Extensions package (all required dependencies will be installed too)

PM> Install-Package StackExchange.Redis.Extensions.Newtonsoft

Unable To Read Package

If the following error occurs
Install-Package : Unable to read package from path 'Newtonsoft.Json.7.0.1\Newtonsoft.Json.7.0.1.nupkg'.
  1. Move the Src\packages\Newtonsoft.Json.7.0.1 directory outside the packages folder (Desktop for example)
  2. Execute Install-Package StackExchange.Redis.Extensions.Newtonsoft again
  3. If the versions are different move back Newtonsoft.Json.7.0.1 directory

Result

3. Implementation

Add the new CacheService class in the project

// -----------------------------------------------
// This file is part of the LayerCake Generator.
//
// Copyright (c) 2012, 2015 LayerCake Generator.
// http://www.layercake-generator.net
// -----------------------------------------------

namespace Externals.RedisCache
{
    using StackExchange.Redis.Extensions.Core;
    using StackExchange.Redis.Extensions.Newtonsoft;
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    /// 
    /// A Redis implementation (System.ICacheService implementation).
    /// Redis-64 v2.8.19, StackExchange.Redis v1.0.450, StackExchange.Redis.Extensions.Core v1.1.10.0, StackExchange.Redis.Extensions.Newtonsoft v1.1.7.0.
    /// 
    public class CacheService : ICacheService
    {
        #region [ Members ]
    
        private static readonly StackExchangeRedisCacheClient _cacheClient = null;
        private static readonly ICacheStatistics _statistics = null;
    
        #endregion
    
        #region [ Constructors ]
    
        static CacheService()
        {
            _cacheClient = new StackExchangeRedisCacheClient(new NewtonsoftSerializer());
            _statistics = new CacheStatistics();
        }
    
        /// 
        /// Initializes a new instance of the RedisCacheService class.
        /// 
        public CacheService()
        {
        }
    
        /// 
        /// Destructor.
        /// 
        ~CacheService()
        {
            this.Dispose(false);
        }
    
        #endregion
    
        #region [ ICacheService Implementation ]
    
        #region [ Synchronous Methods ]
    
        /// 
        /// Adds a CacheItem object to the cache. If the key already exists, the cache is updated with the new data.
        /// 
        ///
        /// 
        /// CacheItem object.
        /// 
        public bool Add(CacheItem cacheItem)
        {
            // RedisServerException: 'ERR invalid expire time in setex'
            // -> the expiration value has a bad value
    
            return _cacheClient.Add(cacheItem.Key, cacheItem.Data, cacheItem.Expiration);
        }
    
        /// 
        /// Adds a new object to the cache with expiration TimeSpan.
        /// If the key already exists, the cache is updated with the new data.
        /// 
        ///
        /// 
        /// Unique key.
        /// 
        ///
        /// 
        /// Object to add to the cache.
        /// 
        ///
        /// 
        /// Expiration TimeSpan.
        /// 
        public bool Add(string key, object data, TimeSpan timeSpan)
        {
            // RedisServerException: 'ERR invalid expire time in setex'
            // -> the expiration value is out of range
    
            return _cacheClient.Add(key, data, timeSpan);
        }
    
        /// 
        /// Gets an object from the cache given its unique key.
        /// 
        ///
        /// 
        /// The type of the retrieved object.
        /// 
        ///
        /// 
        /// Unique key.
        /// 
        ///
        /// 
        /// The retrieved object. If not found returns null.
        /// 
        public T Get<T>(string key) where T : class
        {
            ((CacheStatistics)_statistics).IncrementRequestCount();
    
            var data = _cacheClient.Get<T>(key);
    
            if (data == null)
            {
                ((CacheStatistics)_statistics).IncrementMissCount();
            }
            else
            {
                ((CacheStatistics)_statistics).IncrementHitCount();
            }
    
            return data;
        }
    
        /// 
        /// Gets an object from the cache given its unique key.
        /// 
        ///
        /// 
        /// The type of the retrieved object.
        /// 
        ///
        /// 
        /// Unique key.
        /// 
        ///
        /// 
        /// Function to execute when the key is not present in the cache.
        /// 
        ///
        /// 
        /// Expiration DateTime.
        /// 
        ///
        /// 
        /// The retrieved object. If not found returns null.
        /// 
        public T Get<T>(string key, Func<T> whenNull, DateTime expiration) where T : class
        {
            var item = this.Get<T>(key);
            if (item == null)
            {
                item = whenNull();
                if (item != null)
                {
                    this.Add(new CacheItem { Key = key, Data = item, Expiration = expiration });
                }
            }
    
            return item;
        }
    
        /// 
        /// Gets an object from the cache given its unique key.
        /// 
        ///
        /// 
        /// The type of the retrieved object.
        /// 
        ///
        /// 
        /// Unique key.
        /// 
        ///
        /// 
        /// Function to execute when the key is not present in the cache.
        /// 
        ///
        /// 
        /// Expiration TimeSpan.
        /// 
        ///
        /// 
        /// The retrieved object. If not found returns null.
        /// 
        public T Get<T>(string key, Func<T> whenNull, TimeSpan expiration) where T : class
        {
            return this.Get<T>(key, whenNull, DateTime.Now.AddMilliseconds(expiration.TotalMilliseconds));
        }
    
        /// 
        /// Removes an object from the cache given its unique key.
        /// 
        ///
        /// 
        /// Unique key.
        /// 
        ///
        /// 
        /// True if the object has been removed from the cache; otherwise, false.
        /// 
        public bool Remove(string key)
        {
            return _cacheClient.Remove(key);
        }
    
        /// 
        /// Removes all the objects having the given tag value from the cache.
        /// 
        ///
        /// 
        /// Tag value.
        /// 
        ///
        /// 
        /// The number of objects removed.
        /// 
        public int RemoveByTag(string tag)
        {
            var keys = _cacheClient.SearchKeys(tag);
    
            _cacheClient.RemoveAll(keys);
    
            return keys.Count();
        }
    
        #endregion
    
        #region [ Asynchronous Methods ]
    
        public async Task<bool> AddAsync(CacheItem cacheItem)
        {
            return await _cacheClient.AddAsync(cacheItem.Key, cacheItem.Data, cacheItem.Expiration);
        }
    
        public async Task<bool> AddAsync(string key, object data, TimeSpan timeSpan)
        {
            return await _cacheClient.AddAsync(key, data, timeSpan);
        }
    
        public async Task<T> GetAsync<T>(string key) where T : class
        {
            ((CacheStatistics)_statistics).IncrementRequestCount();
    
            var data = await _cacheClient.GetAsync<T>(key);
    
            if (data == null)
            {
                ((CacheStatistics)_statistics).IncrementMissCount();
            }
            else
            {
                ((CacheStatistics)_statistics).IncrementHitCount();
            }
    
            return data;
        }
    
        public async Task<T> GetAsync<T>(string key, Func<T> whenNull, DateTime expiration) where T : class
        {
            var item = await _cacheClient.GetAsync<T>(key);
            if (item == null)
            {
                item = whenNull();
                if (item != null)
                {
                    await this.AddAsync(new CacheItem { Key = key, Data = item, Expiration = expiration });
                }
            }
    
            return item;
        }
    
        public async Task<T> GetAsync<T>(string key, Func<T> whenNull, TimeSpan expiration) where T : class
        {
            return await this.GetAsync<T>(key, whenNull, DateTime.Now.AddMilliseconds(expiration.TotalMilliseconds));
        }
    
        public async Task<bool> RemoveAsync(string key)
        {
            return await _cacheClient.RemoveAsync(key);
        }
    
        public async Task<int> RemoveByTagAsync(string tag)
        {
            return await _cacheClient.SearchKeysAsync(tag)
                                     .ContinueWith<int>(result =>
            {
                _cacheClient.RemoveAllAsync(result.Result);
                return result.Result.Count();
            });
        }
    
        #endregion
    
        #region [ Properties ]
    
        /// 
        /// Gets the cache statistics.
        /// 
        public ICacheStatistics Statistics
        {
            get
            {
                var key = _cacheClient.GetInfo().Single(i => i.Value.StartsWith("keys=")).Value;
                var data = key.Split(',', '=');
    
                ((CacheStatistics)_statistics).ItemCount = TypeHelper.To<int>(data[1]);
    
                return _statistics;
            }
        }
    
        #endregion
    
        #endregion
    
        #region [ IDisposable Implementation ]
    
        private bool _isDisposed = false;
    
        /// 
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// 
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        /// 
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// 
        ///
        /// 
        /// For internal use.
        /// 
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (!_isDisposed)
                {
                    // Nothing because _cacheClient is a static instance
    
                    _isDisposed = true;
                }
            }
        }
    
        #endregion
    }
}

4. Web.config (server-side)

Edit the Web.config file (of the WebServices project and/or possible ASP.NET WebSite depending on your needs)

  1. Add the 2 missing sections
  2. Change the implementation attribute with the new value Externals.RedisCache.CacheService, Externals.RedisCache
 version="1.0" encoding="utf-8" ?>

	
  
    ...
    
    
... interface="System.ICacheService, System.Extensions" implementation="Externals.RedisCache.CacheService, Externals.RedisCache" instancingMode="Singleton"/>

Reference

Do not forget to add a reference on the  Externals.RedisCache project!

How to run Redis

To run Redis execute  Src\packages\Redis-64.2.8.19\redis-server.exe


你可能感兴趣的:(db,c#,sql,server)