CharlesChen's Technical Space

简单实用是我一直在软件开发追求的目标(I Focus on. Net technology, to make the greatest efforts to enjoy the best of life.)
Not the best, only better
  博客园  :: 首页  :: 联系 :: 订阅 订阅  :: 管理

     不久前发表了一篇关于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;
        }

 配置文件的格式和前面一样的:(路径不同但这对缓存无影响

Code

 Navigate类也前一样:

   protected class Navigator
        {
            
#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()方法的重载。

m_CacheManager.Add(key, value, new CacheDependency(depedencyFile), Cache.NoAbsoluteExpiration,Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, new CacheItemRemovedCallback(LogCacheItemRemoved));

 

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:

Charles.C.Chen@newegg.net

gotosunny@msn.com

                                                                                                                                                                  2008-9-15