不久前发表了一篇关于xml文件读取在项目中的灵活运用:移动项目开发笔记(动态生成xml文件生成导航菜单) 其中没有考虑到性能问题。每次服务器都要从xml文件读取信息。加重了服务器的负担。这对项目来说无疑是一个比较大的风险。下面我来说说如何解决这个性能问题:
最容易想到的方法是用缓存Cache来实现:先把代码贴出来再解释:
using System.Web.Caching;
private static Cache m_CacheManager=System.Web.HttpRuntime.Cache;
public void Render()
{
StringBuilder sb = new StringBuilder();
List<Navigator> list = GetFromCache();
foreach (Navigator navigator in list)
{
sb.AppendFormat(@"<a href='{0}'>{1}</a> | ", navigator.Url, navigator.Name);
}
this.ltlNavigator.Text = sb.ToString().Remove(sb.Length - 1);
}
private List<Navigator> GetFromCache()
{
List<Navigator> navigates = new List<Navigator>();
if (m_CacheManager["Navigate"] == null)
{
string path =
HttpContext.Current.Server.MapPath(
UrlHelper.GetClientUrl(ConfigurationManager.AppSettings["HeadNavigatorFilePath"]));
XmlDocument doc = new XmlDocument();
doc.Load(path);
XmlNodeList nodes = doc.SelectNodes("/root/*");
foreach (XmlNode node in nodes)
{
Navigator navigator = new Navigator();
navigator.Name = node.Attributes["name"].InnerText;
navigator.Url = ResolveUrl(node.Attributes["url"].InnerText);
navigates.Add(navigator);
}
AddToCache("Navigate", navigates, path);
}
else
{
navigates = m_CacheManager["Navigate"] as List<Navigator>;
}
return navigates;
}
private void AddToCache(string key, object value, string depedencyFile)
{
m_CacheManager.Add(key, value, new CacheDependency(depedencyFile), Cache.NoAbsoluteExpiration,Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, new CacheItemRemovedCallback(LogCacheItemRemoved));
}
private static void LogCacheItemRemoved(string key, Object obj, CacheItemRemovedReason reason)
{
return;
}
配置文件的格式和前面一样的:(路径不同但这对缓存无影响)
Navigate类也前一样:
{
#region Private Field
private string m_name;
private string m_url;
#endregion
#region Pubilc Property
public string Name
{
get
{
return m_name;
}
set
{
m_name = value;
}
}
public string Url
{
get
{
return m_url;
}
set
{
m_url = value;
}
}
#endregion
}
上面的代码比起上一篇发表的代码实现方式增加缓存:第一次加载时候从xml文件中读取后立即存放到缓存中,以后读取文件后就直接从缓存中读取,而不用每次都从xml文件读取。这样的减轻了服务器的负担,提高了性能。也就增强了用户的体验。
下面说说上面代码中的一些细节问题:
1.把对象放入缓存中可以直接用m_CacheManager["Navigate"] =Object,但是这样的话Object对象会一直缓存起来,直到服务器重启就可以过期。也就是说当更改服务器上的配置文件时候,用户不能马上看到更新后的效果。只有等服务器IIS重启后才能刷新。这样就不能满足用户的要求。
最好的方法是用m_CacheManager.Insert()方法和m_CacheManager.Add()方法,他们的区别如下:
Add:
1.将指定项添加到 Cache 对象,该对象具有依赖项、过期和优先级策略以及一个委托(可用于在从 Cache 移除插入项时通知应用程序)。如果 Cache 中已保存了具有相同 key 参数的项,则对此方法的调用将失败。若要使用相同的 key 参数改写现有的 Cache 项,请使用 Insert 方法。
2.Add()方法返回对已缓存对象的引用。
Insert:
1.向 Cache 对象插入项。使用此方法的某一版本改写具有相同 key 参数的现有 Cache 项。
2.没有任何返回值.
所以上面的实例用了m_CacheManager.Add()方法的重载。
2.上面的重载方法中包含了一个new CacheDependency()对象,它的作用是:当配置的dependencyFile文件发生变化的时候是,服务器的的Cache["Navigate"]立即过期,下次访问时候由于 m_CacheManager["Navigate"] == null 为true而不从Cache中读取,从而读取xml文件中的信息,保证用户看到的效果和服务器上最新的修改完全一样。这样就解决了由m_CacheManager["Navigate"]=object直接赋值引起的弊端。
3. 重载方法中还可以设置过期时间。(生命周期)Cache对象的生存周期,分2种,绝对生存周期absoluteExpiration和动态生存周期slidingExpiration。
absoluteExpiration:Cache对象的生存周期为定义的时间,从定义到结束,时间既是所定义的时间:
Cache.Insert("name","pierce",null,DateTime.Now.AddMinutes(15),TimeSpan.Zero);
name对象的生存周期为15分钟。
slidingExpiration:Cache对象的生存时间为最后一次使用的时间+定义的时间:
Cache.Insert("name","pierce",null,System.Web.Caching.Cache.NoAbsoluteExpiration,TimeSpan.FromMinutes(15));
4. 重载参数new CacheItemRemovedCallback()是一个委托。也就说当Cache到期后执行的方法LogCacheItemRemoved()方法,通知应用程序缓存到期.
该示例将使用LogCacheItemRemoved()没有写任何方法,当然你可以用来记录日志。也就是说:
方法中定义的任何逻辑来记录缓存中的数据到期的原因。通过在从缓存中删除项时记录这些项并记录删除的原因。
最后生成的效果图也前一样:只不过这次加了缓存机制,减轻了服务器的负担,提高了性能。
希望我希望这篇文章能给朋友们带来帮助,也希望朋友们能提出宝贵的意见,共同分享知识。谢谢
Chares Chen
MSN:
2008-9-15