自定义缓存依赖项的设计
从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();
}