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

ASP.NET
C#教程:简化的初始化
C#教程:隐式类型的局部变量
ASP.NET 2.0教程:Bind标签和Eval标签
用C#语言获取CPU利用率
ASP.Net实例:直接在邮件中内联附件内嵌图片
ASP.NET教程:性能优化的方法
ASP.NET开发方式的四层架构的Web应用系统构造
BasicHTTP-唯一能直接与Java交互的方式
ASP.NET教程:截取字符串
如何用ASP.NET实现多附件上传?
.Net程序员必读:八个实用网站推荐
.NET环境下为网站增加IP过滤功能
在.Net框架类库中如何使用定时器类
Asp.net是可以帮你实现Urlrewrite的
.NET开发过程中易被忽视的问题
ASP.NET教程:多个Set排列算法
c# 分布式事务以及MSDTC
解决ASP.NET2.0网站中对路径访问被拒绝问题
ASP.NET通过WMI创建站点添加虚拟目录和主机头
VS 2008完美地支持JavaScript和ASP.NET AJAX

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


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-11   浏览: 96 ::
收藏到网摘: 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;
}
}
}