自定义缓存依赖项的设计
从ASP.NET 2.0开始,CacheDependency类是可继承的,即我们能够从它派生出自己的类,实现通过外部的事件源使缓存项失效的机制。
基类CacheDependency的扩展
为能将派生类整合到现有的ASP.NET缓存基础结构中,并对其提供充分的支持,相对于ASP 1.x版本,CacheDependency类加入了许多公共成员和受保护成员。详见下表:
自定义依赖项要依靠其父类与Cache对象进行交互。CacheDependency的派生类会调用NotifyDependencyChanged方法,以便通知基类依赖项已被更改。作为响应,基类会更新HasChanged和UtcLastModified属性的值。若要释放自定义的缓存依赖项对象,可调用DependencyDispose方法来执行清理代码。
更改通知的获取
自定义的依赖项对象必须能接收它所监视的外部源的通知。当检测到源发出的更改通知后,依赖项应使用父类的基础结构通知缓存该事件的发生。
AggregateCacheDependency类
自ASP.NET 2.0版开始,我们不仅可以创建单个针对某项的依赖项,还可以创建聚合依赖项。如,可使缓存项同时依赖于两个不同的磁盘文件:
CacheDependency dep1 = new CacheDependency(fileName1);CacheDependency dep2 = new CacheDependency(fileName2);CacheDependency[] deps = {dep1, dep2};AggregateCacheDependency aggDep = new AggregateCacheDependency();aggDep.Add(deps);Cache.Insert( " MyData " , data, aggDep); AggregateCacheDependency作为自定义缓存依赖项对象继承自CacheDependency类。
针对XML数据的缓存依赖项
假设您决定缓存XML文件中的关键数据,但仍希望在应用程序运行时检查该文件的更改,如何实现呢?您也许会想设置一个文件依赖项即可。但如果我们仅关注XML文件中的某个节点呢?文件依赖的问题在于,即使更改的节点与我们所关注的节点无关,我们仍会收到更改通知。这时,我们需要创建一种专用的缓存依赖项,只监视XML文件中给定XPath表达式所指的值。
提示:如果目标地数据源提供了异步通知机制的完整内建支持(如SQL Server 2005的命令通知机制),则可直接使用。否则,否要对数据源更改进行检测,只能对该资源以合理的周期进行轮询。
XmlDataCacheDependency类的设计
为实现以上功能,我们要定义一个自定义的依赖项类,在序列化时缓存当前值,并周期性地读取该文件来检查更改。若检测到更改,便使绑定到该依赖项的缓存项失效。
自定义依赖项的实现
下面的代码给出了自定义的XmlDataCacheDependency类的实现:
public class XmlDataCacheDependency : CacheDependency{ // 定时器 Timer _timer; // 轮询间隔 int _pollSecs = 10 ; // 待监测的XML文件名 string _fileName; // XPath表达式 string _xpathExpression; // 被监视的XML节点当前值 string _currentValue public XmlDataCacheDependency( string file, string xpath, int pollTime) { _fileName = file; _xpathExpression = xpath; _pollSecs = pollTime; // 获取当前监测节点值 _currentValue = CheckFile(); int ms = _pollSecs * 1000 ; // 定义定时委托 TimerCallback cb = new TimerCallback(xmlDataCallback); // 创建timer对象 _timer = new Timer(cb, this , ms, ms); } public string CurrentValue { get { return _currentValue; } } public void XmlDataCallback( object sender) { XmlDataCacheDependency dep = (XmlDataCacheDependency)sender; // 获取当前节点值 string value = CheckFile(); // 如果当前节点值被更改,则发出更改通知 if ( ! String.Equals(_currentValue, value) dep.NotifyDependencyChanged(dep, EventArgs.Empty); } public string CheckFile() { XmlDocument doc = new XmlDocument(); doc.Load(_fileName); XmlNode node = doc.SelectSingleNode(_xpathExpression); return node.InnerText; } protected override void DependencyDispose() { // 释放Timer对象 _timer.Dispose(); _timer = null ; // 调用基类的DependencyDispose方法 base .DependencyDispose(); }} 在页面中使用XmlDataCacheDependency:
protected const string CacheKeyName = " MyData " ; protected void Page_load( object sender, EventArgs e){ if ( ! IsPostBack) { // 创建Xml依赖 XmlDataCacheDependency dep = new XmlDataCacheDependency( Server.MapPath( " employees.xml " ), " MyDataSet/NorthwindEmployees/Employee[employeeid=3]/lastname " , 1 ); // 创建缓存 Cache.Insert(CacheKeyName, dep.CurrentValue, dep); } // 显示 Msg.Text = Display();}