C# 内存缓存&x27;s幻灯片过期-可选幻灯片过期?

C# 内存缓存&x27;s幻灯片过期-可选幻灯片过期?,c#,caching,memorycache,C#,Caching,Memorycache,我和你一起工作 我已经创建了缓存,并使用5分钟的滑动过期时间向其中添加了一个条目: MemoryCache.Default.Set("Key", "Value", new CacheItemPolicy { SlidingExpiration = new TimeSpan(0, 5, 0) }); // Resets the sliding expiration: MemoryCache.Default.Get("Key"); 如果在5分钟内未访问此条目,则会将其从缓存中删除。如果访

我和你一起工作

我已经创建了缓存,并使用5分钟的滑动过期时间向其中添加了一个条目:

MemoryCache.Default.Set("Key", "Value", new CacheItemPolicy
{
    SlidingExpiration = new TimeSpan(0, 5, 0)
});
// Resets the sliding expiration:
MemoryCache.Default.Get("Key");
如果在5分钟内未访问此条目,则会将其从缓存中删除。如果访问,则滑动过期计时器将重置回5分钟:

MemoryCache.Default.Set("Key", "Value", new CacheItemPolicy
{
    SlidingExpiration = new TimeSpan(0, 5, 0)
});
// Resets the sliding expiration:
MemoryCache.Default.Get("Key");
我希望能够有选择地从缓存中检索条目,而无需重置滑动过期计时器

这似乎不可能,但我想确认一下


欲了解我的具体需求:

  • 我有两个实体,Report和ReportData。ReportData查询速度慢。报表和报表数据都缓存到两个单独的内存缓存中

  • 报告MemoryCache在四天后过期。ReportData MemoryCache在30分钟后过期

  • 每当ReportData自然过期时,它都会自动刷新并重新缓存。这样可以确保所有ReportData条目都是新的

  • 如果用户在4天内未请求报告,则会将其从缓存中删除,并删除相应的ReportData。每当用户请求报告时,应重新启动此4天计时器

问题是:刷新ReportData需要引用Report。通过缓存获取对报表的引用会导致缓存计时器重新启动。这是不可取的。只有当用户请求报告时,报告缓存计时器才应重新启动

一个潜在的解决方案是引入第三个缓存。另一个缓存将允许外部访问与内部访问的不同过期行为

这是我目前的代码:

/// <summary>
/// A service for caching Custom reports.
/// </summary>
public class ReportCachingService : ServiceBase
{
    /// <summary>
    /// Refresh report data every N minutes.
    /// </summary>
    private int ReportDataRefreshInterval { get; set; }

    /// <summary>
    /// Remember reports for N days.
    /// </summary>
    private int MaxReportAge { get; set; }
    private MemoryCache ReportDataCache { get; set; }
    private MemoryCache ReportCache { get; set; }
    private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

    public ReportCachingService()
    {
        Logger.Info("ReportCachingService initializing...");
        LoadConfiguration();
        // Note: The name 'ReportDataCache' must be kept in-sync w/ App.config namedCache entry.
        ReportDataCache = new MemoryCache("ReportDataCache");
        ReportCache = new MemoryCache("ReportCache");
        Logger.Info("ReportCachingService successfully started.");
    }

    public ReportData GetReportData(int reportID)
    {
        string key = reportID.ToString();
        ReportData reportData = ReportDataCache.Get(key) as ReportData ?? GetAndCacheReportData(reportID);

        return reportData;
    }

    public Report GetReport(int reportID)
    {
        string key = reportID.ToString();
        Report report = ReportCache.Get(key) as Report ?? GetAndCacheReport(reportID);

        return report;
    }

    private void LoadConfiguration()
    {
        try
        {
            ReportDataRefreshInterval = GetConfigValue("ReportDataRefreshInterval");
            MaxReportAge = GetConfigValue("MaxReportAge"); ;
            Logger.Info(string.Format("Configuration loaded. Report data will refresh every {0} minutes. Maximum report age is {1} day(s).", ReportDataRefreshInterval, MaxReportAge));
        }
        catch (Exception exception)
        {
            Logger.Error("Error loading configuration.", exception);
            throw;
        }
    }

    private static int GetConfigValue(string key)
    {
        string configValueString = ConfigurationManager.AppSettings[key];
        if (string.IsNullOrEmpty(configValueString))
        {
            throw new Exception(string.Format("Failed to find {0} in App.config", key));
        }

        int configValue;
        bool isValidConfigValue = int.TryParse(configValueString, out configValue);

        if (!isValidConfigValue)
        {
            throw new Exception(string.Format("{0} was found in App.config, but is not a valid integer value.", key));
        }

        return configValue;
    }

    private ReportData GetAndCacheReportData(int reportID)
    {
        Report report = GetReport(reportID);
        ReportData reportData = report.GetData(false, "Administrator");

        if (reportData == null)
        {
            string errorMessage = string.Format("Failed to find reportData for report with ID: {0}", reportID);
            Logger.Error(errorMessage);
            throw new Exception(errorMessage);
        }

        // SlidingExpiration forces cache expiration to refresh when an entry is accessed.
        TimeSpan reportDataCacheExpiration = new TimeSpan(0, ReportDataRefreshInterval, 0);
        string key = reportID.ToString();
        ReportDataCache.Set(key, reportData, new CacheItemPolicy
        {
            SlidingExpiration = reportDataCacheExpiration,
            UpdateCallback = OnReportDataUpdate
        });

        return reportData;
    }

    private Report GetAndCacheReport(int reportID)
    {
        // If the ReportCache does not contain the Report - attempt to load it from DB.
        Report report = Report.Load(reportID);

        if (report == null)
        {
            string errorMessage = string.Format("Failed to find report with ID: {0}", reportID);
            Logger.Error(errorMessage);
            throw new Exception(errorMessage);
        }

        // SlidingExpiration forces cache expiration to refresh when an entry is accessed.
        TimeSpan reportCacheExpiration = new TimeSpan(MaxReportAge, 0, 0, 0);
        string key = reportID.ToString();
        ReportCache.Set(key, report, new CacheItemPolicy
        {
            SlidingExpiration = reportCacheExpiration,
            RemovedCallback = OnReportRemoved
        });

        return report;
    }

    private void OnReportRemoved(CacheEntryRemovedArguments arguments)
    {
        Logger.DebugFormat("Report with ID {0} has expired with reason: {1}.", arguments.CacheItem.Key, arguments.RemovedReason);
        // Clear known ReportData for a given Report whenever the Report expires.
        ReportDataCache.Remove(arguments.CacheItem.Key);
    }

    private void OnReportDataUpdate(CacheEntryUpdateArguments arguments)
    {
        Logger.DebugFormat("ReportData for report with ID {0} has updated with reason: {1}.", arguments.UpdatedCacheItem.Key, arguments.RemovedReason);
        // Expired ReportData should be automatically refreshed by loading fresh values from the DB.
        if (arguments.RemovedReason == CacheEntryRemovedReason.Expired)
        {
            int reportID = int.Parse(arguments.Key);
            GetAndCacheReportData(reportID);
        }
    }
}
//
///用于缓存自定义报表的服务。
/// 
公共类ReportCachingService:ServiceBase
{
/// 
///每N分钟刷新一次报告数据。
/// 
私有int ReportDataRefreshInterval{get;set;}
/// 
///记住N天的报告。
/// 
private int MaxReportAge{get;set;}
私有内存缓存ReportDataCache{get;set;}
私有内存缓存报告缓存{get;set;}
私有静态只读ILog Logger=LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
公共报告CachingService()
{
Logger.Info(“ReportCachingService初始化…”);
LoadConfiguration();
//注意:名称“ReportDataCache”必须与App.config namedCache条目保持同步。
ReportDataCache=newmemorycache(“ReportDataCache”);
ReportCache=newmemorycache(“ReportCache”);
Info(“ReportCachingService已成功启动”);
}
public ReportData GetReportData(int reportID)
{
string key=reportID.ToString();
ReportData ReportData=ReportDataCache.Get(键)作为ReportData??GetAndCacheReportData(reportID);
返回报告数据;
}
公共报告GetReport(int reportID)
{
string key=reportID.ToString();
Report Report=ReportCache.Get(key)as Report??GetAndCacheReport(reportID);
返回报告;
}
私有void LoadConfiguration()
{
尝试
{
ReportDataRefreshInterval=GetConfigValue(“ReportDataRefreshInterval”);
MaxReportAgree=GetConfigValue(“MaxReportAgree”);
Logger.Info(string.Format(“已加载配置。报告数据将每{0}分钟刷新一次。最大报告期限为{1}天。”,ReportDataRefreshInterval,MaxReportAgage));
}
捕获(异常)
{
Logger.Error(“加载配置时出错”,异常);
投掷;
}
}
私有静态int GetConfigValue(字符串键)
{
string configValueString=ConfigurationManager.AppSettings[key];
if(string.IsNullOrEmpty(configValueString))
{
抛出新异常(string.Format(“未能在App.config中找到{0}”,key));
}
int配置值;
bool isValidConfigValue=int.TryParse(configValueString,out configValue);
如果(!isValidConfigValue)
{
抛出新异常(string.Format(“{0}在App.config中找到,但不是有效的整数值。”,key));
}
返回配置值;
}
私有ReportData GetAndCacheReportData(int reportID)
{
报告=获取报告(报告ID);
ReportData ReportData=report.GetData(false,“管理员”);
if(reportData==null)
{
string errorMessage=string.Format(“未能找到ID为{0}的报表的reportData”,reportID);
Logger.Error(错误消息);
抛出新异常(errorMessage);
}
//滑动过期强制缓存过期在访问条目时刷新。
TimeSpan reportDataCacheExpiration=新的TimeSpan(0,ReportDataRefreshInterval,0);
string key=reportID.ToString();
ReportDataCache.Set(键,reportData,新CacheItemPolicy
{
SlidingExpiration=reportDataCacheExpiration,
UpdateCallback=OnReportDataUpdate
});
返回报告数据;
}
私有报表GetAndCacheReport(int reportID)
{
//如果ReportCache不包含报告-请尝试从DB加载它。
Report=Report.Load(reportID);
如果(报告==null)
{
string errorMessage=string.Format(“找不到ID为{0}的报表”,reportID);
Logger.Error(错误消息);
抛出新异常(errorMessage);
}
//滑动过期强制缓存过期在访问条目时刷新。
TimeSpan reportCacheExpiration=新的TimeSpan(MaxReport文学,0,0,0);
string key=reportID.ToString();
ReportCache.Set(键、报表、新CacheItemPolicy
{
SlidingExpiration=reportCacheExpiration,
RemovedCallback=OnReportRemoved
});