asp.net SAF 中缓存服务的实现第3/5页
更新时间:2008年08月08日 21:28:49 作者:
对缓存的兴趣源于张子阳写的一篇文章《SAF 中缓存服务的实现》中的一个例子:
Cache类还包含两个私有方法。PreparePath()用于对输入的Xpath进行格式化,使其以构造函数中创建的根节点("Cache")作为根结点(这样做是可以使你在添加/获取对象时免去写根结点的麻烦);CreateNode() 用于根据XPath逐层深入地创建Xml结点。 C#复制代码
// 根据 XPath 创建一个结点
private XmlNode CreateNode(string xpath) {
string[] xpathArray = xpath.Split('/');
string nodePath = "";
// 父节点初始化
XmlNode parentNode = (XmlNode)rootMap;
// 逐层深入 XPath 各层级,如果结点不存在则创建
// 比如 /DvdStore/Dvd/NoOneLivesForever
for (int i = 1; i < xpathArray.Length; i++) {
XmlNode node = rootMap.SelectSingleNode(nodePath + "/" + xpathArray[i]);
if (node == null) {
XmlElement newElement = rootMap.OwnerDocument.CreateElement(xpathArray[i]); // 创建结点
parentNode.AppendChild(newElement);
}
// 创建新路径,更新父节点,进入下一级
nodePath = nodePath + "/" + xpathArray[i];
parentNode = rootMap.SelectSingleNode(nodePath);
}
return parentNode;
}
// 构建 XPath,使其以 /Cache 为根结点,并清除多于的"/"字符
private string PrepareXPath(string xpath) {
string[] xpathArray = xpath.Split('/');
xpath = "/Cache"; // 这里的名称需与构造函数中创建的根结点名称对应
foreach (string s in xpathArray) {
if (s != "") {
xpath += "/" + s;
}
}
return xpath;
}
AddItem()方法用于向缓存中添加对象,包括了下面几个步骤:
1、根据输入的XPath判断到达 叶结点 的路径是否已经存在,如果不存在,调用上面的CreateNode()方法,逐层创建结点。
2、生成GUID,在组结点下创建 XmlNode 叶结点,为叶结点添加属性Key,并将值设为GUID。
3、将对象保存至实际的位置,默认实现是一个Hashtable,通过调用ICacheStrategy.AddItem()方法来完成,并将Hashtable的Key设置为GUID。
NOTE: 为了说明方便,这里有一个我对一类结点的命名--“组结点”。假设有XPath路径:/Cache/BookStore/Book/Title,那么/Cache/BookStore/Book即为“组结点”,称其为“组结点”,是因为其下可包含多个叶结点,比如 /Cache/BookStore/Book/Author 包含了叶结点 Author;而/Cache/BookStore/Book/Title 中的Title为叶结点,GUID存储在叶结点的属性中。需要注意 组结点 和 叶结点是相对的,对于路径 /Cache/BookStore/Book 来说,它的组结点就是“/Cache/BookStore”,而 Book是它的叶结点。
下面是AddItem()方法的完整代码:
复制代码 代码如下:
// 添加对象,对象实际上还是添加到ICacheStrategy指定的存储位置,
// 动态创建的 Xml 结点仅保存了对象的Id(key),用于映射两者间的关系
public virtual void AddItem(string xpath, object obj) {
// 获取 Xpath,例如 /Cache/BookStore/Book/Title
string newXpath = PrepareXPath(xpath);
int separator = newXpath.LastIndexOf("/");
// 获取组结点的层叠顺序 ,例如 /Cache/BookStore/Book
string group = newXpath.Substring(0, separator);
// 获取叶结点名称,例如 Title
string element = newXpath.Substring(separator + 1);
// 获取组结点
XmlNode groupNode = rootMap.SelectSingleNode(group);
// 如果组结点不存在,创建之
if (groupNode == null) {
lock (this) {
groupNode = CreateNode(group);
}
}
// 创建一个唯一的 key ,用来映射 Xml 和对象的主键
string key = Guid.NewGuid().ToString();
// 创建一个新结点
XmlElement objectElement = rootMap.OwnerDocument.CreateElement(element);
// 创建结点属性 key
XmlAttribute objectAttribute = rootMap.OwnerDocument.CreateAttribute("key");
// 设置属性值为 刚才生成的 Guid
objectAttribute.Value = key;
// 将属性添加到结点
objectElement.Attributes.Append(objectAttribute);
// 将结点添加到 groupNode 下面(groupNode为Xpath的层次部分)
groupNode.AppendChild(objectElement);
// 将 key 和 对象添加到实际的存储位置,比如Hashtable
cacheStrategy.AddItem(key, obj);
}
RemoveItem()则用于从缓存中删除对象,它也包含了两个步骤:1、先从Xml文档树中删除结点;2、再从实际的存储位置(Hashtable)中删除对象。这里需要注意的是:如果XPath指定的是一个叶结点,那么直接删除该结点;如果XPath指定的是组结点,那么需要删除组结点下的所有结点。代码如下:
C#复制代码
// 根据 XPath 删除对象
public virtual void RemoveItem(string xpath) {
xpath = PrepareXPath(xpath);
XmlNode result = rootMap.SelectSingleNode(xpath);
string key; // 对象的Id
// 如果 result 是一个组结点(含有子结点)
if (result.HasChildNodes) {
// 选择所有包含有key属性的的结点
XmlNodeList nodeList = result.SelectNodes("descendant::*[@key]");
foreach (XmlNode node in nodeList) {
key = node.Attributes["key"].Value;
// 从 Xml 文档中删除结点
node.ParentNode.RemoveChild(node);
// 从实际存储中删除结点
cacheStrategy.RemoveItem(key);
}
} else { // 如果 result 是一个叶结点(不含子结点)
key = result.Attributes["key"].Value;
result.ParentNode.RemoveChild(result);
cacheStrategy.RemoveItem(key);
}
}
相关文章
ASP.NET实现TreeView的XML数据源绑定实例代码
这篇文章介绍了ASP.NET实现TreeView的XML数据源绑定实例代码,有需要的朋友可以参考一下2013-11-11ASP.NET堆和栈二之值类型和引用类型的参数传递和内存分配
这篇文章介绍了ASP.NET堆和栈中值类型和引用类型的参数传递和内存分配,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2022-08-08如何在ASP.NET Core中给上传图片功能添加水印实例代码
这篇文章主要给大家介绍了关于如何在ASP.NET Core中给上传图片功能添加水印的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧2019-02-02asp.net core webapi项目配置全局路由的方法示例
这篇文章主要介绍了asp.net core webapi项目配置全局路由的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧2018-09-09
最新评论