asp.net SAF 中缓存服务的实现
更新时间:2008年08月08日 21:28:49 作者:
对缓存的兴趣源于张子阳写的一篇文章《SAF 中缓存服务的实现》中的一个例子:
全部代码:
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;
}
}
}
相关文章
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
最新评论