当前位置: 首页 > 图文教程 > 网络编程 > ASP.NET > asp.net SAF 中缓存服务的实现

ASP.NET
AspNetPager与Socut.Data使用方法
asp.net UpdaeProgress的简单用法
asp.net ajaxControlToolkit ValidatorCalloutExtender的简单用法
asp.net 简易生成注册码(数字+大小写字母)
asp.net中利用ashx实现图片防盗链代码
ASP.NET程序中常用代码汇总
ASP.NET 2.0/3.5中直接操作Gridview控件插入新记录
ASP.NET Ajax级联DropDownList实现代码
ASP.NET 2.0写无限级下拉菜单
asp.net Web Services上传和下载文件(完整代码)
asp.net DataGrid控件中弹出详细信息窗口
Asp.NET 多层登陆实现代码
利用Asp.Net回调机制实现进度条
ASP.NET Ref和Out关键字区别分析
Javascript调用Webservice的多种方法
.Net下的签名与混淆图文分析
.Net Compact Framework开发小技巧 推荐
.Net连接Oracle数据库的实现代码
js获取.aspx页面里面的服务器控件和.ascx中的服务器控件值
asp.net下 jquery jason 高效传输数据

ASP.NET 中的 asp.net SAF 中缓存服务的实现


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-11   浏览: 92 ::
收藏到网摘: n/a

对缓存的兴趣源于张子阳写的一篇文章《SAF 中缓存服务的实现》中的一个例子:
复制代码 代码如下:
类型接口
我们先看一下类型的组织,然后再看实现。
ICacheStrategy用于定义如何添加、获取、删除欲进行缓存的对象。实际上,在接口的实体类中要明确使用何种类型来存储对象,是Dictionary还是Hashtable或者其他。
C#
复制代码 代码如下:
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()方法的完整代码:
复制代码 代码如下:
最后的两个方法,GetItem()和GetList()分别用于从缓存中获取单个或者多个对象。值得注意的是当使用GetList()方法时,Xpath应该为到达一个组结点的路径。
复制代码 代码如下:
全部代码:
ICacheStrategy.cs
复制代码 代码如下:

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace CacheService {
// 定义如何添加、获取、删除欲进行缓存的对象
public interface ICacheStrategy {
// 添加对象
void AddItem(string key, object obj);
// 获取对象
object GetItem(string key);
// 删除对象
void RemoveItem(string key);
}

public class DefaultCacheStrategy : ICacheStrategy {
private Hashtable objectStore;
public DefaultCacheStrategy() {
objectStore = new Hashtable();
}
public void AddItem(string key, object obj) {
objectStore.Add(key, obj);
}
public object GetItem(string key) {
return objectStore[key];
}
public void RemoveItem(string key) {
objectStore.Remove(key);
}
}
}

Cache.cs
复制代码 代码如下:

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Collections;
namespace CacheService {
// 使用树形结构来存储对象,有别于Hashtable的平板式结构
// 通过 XPath 来进行对象获取
public class Cache {
private XmlElement rootMap; // 动态构建的 Xml文档 的根结点
private ICacheStrategy cacheStrategy;
public static readonly Cache Instance = new Cache(); // 实现Singleton模式
private XmlDocument doc = new XmlDocument(); // 构建 Xml文档
// 私有构造函数,用来实现Singleton模式
private Cache() {
// 这里应用了Strategy模式。
// 改进:可以将使用何种Strategy定义到app.config中,然后使用反射来动态创建类型
cacheStrategy = new DefaultCacheStrategy();
// 创建文档根结点,用于映射 实际的数据存储(例如Hashtable) 和 Xml文档
rootMap = doc.CreateElement("Cache");
// 添加根结点
doc.AppendChild(rootMap);
}
// 根据 XPath 获取对象
// 先根据Xpath获得对象的Key,然后再根据Key获取实际对象
public virtual object GetItem(string xpath) {
object obj = null;
xpath = PrepareXPath(xpath);
XmlNode node = rootMap.SelectSingleNode(xpath);
if (node != null) {
// 获取对象的Key
string key = node.Attributes["key"].Value;
// 获取实际对象
obj = cacheStrategy.GetItem(key);
}
return obj;
}

// 获取一组对象,此时xpath为一个组结点
public virtual object[] GetList(string xpath) {
xpath = PrepareXPath(xpath);
XmlNode group = rootMap.SelectSingleNode(xpath);
// 获取该结点下的所有子结点(使用[@key]确保子结点一定包含key属性)
XmlNodeList results = group.SelectNodes(xpath + "/*[@key]");
ArrayList objects = new ArrayList();
string key;
foreach (XmlNode result in results) {
key = result.Attributes["key"].Value;
Object obj = cacheStrategy.GetItem(key);
objects.Add(obj);
}
return (object[])objects.ToArray(typeof(object));
}

// 添加对象,对象实际上还是添加到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);
}

// 根据 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);
}
}

// 根据 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;
}
}
}