using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;
using System.Text;
using System.Threading.Tasks;
namespace AutoLogisticsPH.Common.Utils
{
/// <summary>
/// 基於MemoryCache(內存緩存)的緩存工具類
/// Author:左文俊
/// Date:2017/12/11
/// </summary>
public static class MemoryCacheUtil
{
private static readonly Object _locker = new object(), _locker2 = new object();
/// <summary>
/// 取緩存項,如果不存在則返回空
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public static T GetCacheItem<T>(String key)
{
try
{
return (T)MemoryCache.Default[key];
}
catch
{
return default(T);
}
}
/// <summary>
/// 是否包含指定鍵的緩存項
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static bool Contains(string key)
{
return MemoryCache.Default.Contains(key);
}
/// <summary>
/// 取緩存項,如果不存在則新增緩存項
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="cachePopulate"></param>
/// <param name="slidingExpiration"></param>
/// <param name="absoluteExpiration"></param>
/// <returns></returns>
public static T GetOrAddCacheItem<T>(String key, Func<T> cachePopulate, TimeSpan? slidingExpiration = null, DateTime? absoluteExpiration = null)
{
if (String.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
if (cachePopulate == null) throw new ArgumentNullException("cachePopulate");
if (slidingExpiration == null && absoluteExpiration == null) throw new ArgumentException("Either a sliding expiration or absolute must be provided");
if (MemoryCache.Default[key] == null)
{
lock (_locker)
{
if (MemoryCache.Default[key] == null)
{
T cacheValue = cachePopulate();
if (!typeof(T).IsValueType && ((object)cacheValue) == null) //如果是引用類型且為NULL則不存緩存
{
return cacheValue;
}
var item = new CacheItem(key, cacheValue);
var policy = CreatePolicy(slidingExpiration, absoluteExpiration);
MemoryCache.Default.Add(item, policy);
}
}
}
return (T)MemoryCache.Default[key];
}
/// <summary>
/// 取緩存項,如果不存在則新增緩存項
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="cachePopulate"></param>
/// <param name="dependencyFilePath"></param>
/// <returns></returns>
public static T GetOrAddCacheItem<T>(String key, Func<T> cachePopulate, string dependencyFilePath)
{
if (String.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
if (cachePopulate == null) throw new ArgumentNullException("cachePopulate");
if (MemoryCache.Default[key] == null)
{
lock (_locker2)
{
if (MemoryCache.Default[key] == null)
{
T cacheValue = cachePopulate();
if (!typeof(T).IsValueType && ((object)cacheValue) == null) //如果是引用類型且為NULL則不存緩存
{
return cacheValue;
}
var item = new CacheItem(key, cacheValue);
var policy = CreatePolicy(dependencyFilePath);
MemoryCache.Default.Add(item, policy);
}
}
}
return (T)MemoryCache.Default[key];
}
/// <summary>
/// 移除指定鍵的緩存項
/// </summary>
/// <param name="key"></param>
public static void RemoveCacheItem(string key)
{
try
{
MemoryCache.Default.Remove(key);
}
catch
{ }
}
private static CacheItemPolicy CreatePolicy(TimeSpan? slidingExpiration, DateTime? absoluteExpiration)
{
var policy = new CacheItemPolicy();
if (absoluteExpiration.HasValue)
{
policy.AbsoluteExpiration = absoluteExpiration.Value;
}
else if (slidingExpiration.HasValue)
{
policy.SlidingExpiration = slidingExpiration.Value;
}
policy.Priority = CacheItemPriority.Default;
return policy;
}
private static CacheItemPolicy CreatePolicy(string filePath)
{
CacheItemPolicy policy = new CacheItemPolicy();
policy.ChangeMonitors.Add(new HostFileChangeMonitor(new List<string>() { filePath }));
policy.Priority = CacheItemPriority.Default;
return policy;
}
}
}
支持:可指定絕對過期時間、滑動過期明間、文件依賴 三種緩存方式,目前已在公司各種生產業務項目中有使用。優點是可以根據數據的使用頻率設置緩存有效期,特別是文件依賴緩存,比如:連接字符串讀取一次后,若CONFIG文件沒有改變,則緩存永久有效,一旦CONFIG更改,則緩存失效需重新讀取,保證數據緩存的最大可用性,減少不必要的多次重復讀取CONFIG。
使用示例很簡單:(如下:會在第一次讀取連接字符串並解密后返回給connstr變量,后續直接通過緩存KEY dbConnName直接返回連接字符串的結果,若修改了連接字符串的CONFIG文件,則緩存的項會失效,會重新讀取連接字符串並重新加入到緩存中)
string connstr= MemoryCacheUtil.GetOrAddCacheItem(dbConnName, () =>
{
var connStrSettings = ConfigUtil.GetConnectionString(dbConnName,dbConnectionStringConfigPath);
string dbProdName = connStrSettings.ProviderName;
string dbConnStr = connStrSettings.ConnectionString;
return EncryptUtil.Decrypt(dbConnStr);
}, "緩存依賴文件路路,如:c:\app\app.config");
