小菜梦游Discuz!NT (第三篇 配置文件处理2)

小菜又开始做梦了....睡的好香...
想起了昨天老大交待的事.在修改DNT.config配置文件中的配置项时,程序无法检测到配置文件已经被修改.
小菜沉思了一会儿,想到了解决方案,使用一个定时器Timer,每隔一段时间让它重新加载一下基本配置描述类.
using System;
using System.IO;
using System.Web;
using System.Xml.Serialization;

namespace Discuz.Config
{
    
/// <summary>
    
/// 基本配置文件管理类
    
/// </summary>

    public class BaseConfigFileManager
    
{
        
private static BaseConfigInfo m_configInfo; //基本配置信息描述对象 
        private static string m_configFilePath; //基本配置文件路径
        private static System.Timers.Timer timer = new System.Timers.Timer(); //定时器

        
static BaseConfigFileManager()
        
{
            m_configInfo 
= DeserializeInfo();

            timer.Enabled 
= true//该值指示 Timer 是否应引发 Elapsed 事件 
            timer.Interval = 15000//获取或设置引发 Elapsed 事件的间隔 1.5秒
            timer.AutoReset = true//该值指示 Timer 是应在每次指定的间隔结束时引发 Elapsed 事件,还是仅在指定的间隔第一次结束后引发该事件
            timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
            timer.Start(); 
//通过将 Enabled 设置为 true 开始引发 Elapsed 事件
        }


        
/// <summary>
        
/// 每隔1.5秒重新加载基本配置描述信息
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>

        protected static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        
{
            m_configInfo 
= DeserializeInfo();
        }


        
/// <summary>
        
/// 基本配置文件路径
        
/// </summary>

        private static string ConfigFilePath
        
{
            
get
            
{
                
if (m_configFilePath == null)
                
{
                    HttpContext context 
= HttpContext.Current;
                    m_configFilePath 
= context.Server.MapPath("~/DNT.config");
                }


                
return m_configFilePath;
            }

        }


        
/// <summary>
        
/// 返回基本配置文件信息描述对象
        
/// </summary>

        private static BaseConfigInfo GetBaseConfig
        
{
            
get
            
{
                
return m_configInfo;
            }

        }


        
/// <summary>
        
/// 返回数据库类型
        
/// </summary>

        public static string GetDbType
        
{
            
get
            
{
                
return GetBaseConfig.DbType;
            }

        }


        
/// <summary>
        
/// 反序列化基本配置信息描述类
        
/// </summary>
        
/// <returns></returns>

        private static BaseConfigInfo DeserializeInfo()
        
{
            BaseConfigInfo configInfo;
            FileStream fs 
= null;
            
try
            
{
                fs 
= new FileStream(ConfigFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                XmlSerializer serializer 
= new XmlSerializer(typeof(BaseConfigInfo));
                configInfo 
= (BaseConfigInfo)serializer.Deserialize(fs);
            }

            
catch (Exception ex)
            
{
                
throw ex;
            }

            
finally
            
{
                
if (fs != null)
                    fs.Close();
            }


            
return configInfo;
        }

    }

}

小菜马上对这个解决方案进行了测试Response.Write(Discuz.Config.BaseConfigFileManager.GetDbType);运行...
看到的是SqlServer.然后把DNT.config配置文件中的<DbType>SqlServer</DbType>
修改为<DbType>Access</DbType>
等待1.5秒,然后刷新了下页面,显示Access...哈哈...成功啦...

老大这时走了过来,看小菜的任务完成了如何,看了下代码.问到ConfigFilePath是否需要改成如下这种形式.

/// <summary>
/// 基本配置文件路径
/// </summary>

private static string ConfigFilePath
{
    
get
    
{
        
if (m_configFilePath == null)
        
{
            HttpContext context 
= HttpContext.Current;
            
if (context != null)
            
{
                m_configFilePath 
= context.Server.MapPath("~/DNT.config");
            }

            
else
            
{
                m_configFilePath 
= Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DNT.config");
            }

        }


        
return m_configFilePath;
    }

}

小菜想了想,老大的这段代码和自己的有何不同.
唯一的差别就在于if(context!=null){/*来自Web的请求*/}else{/*不是来自Web的请求*/}

什么情况下会出现不是来自Web的请求呢? 当请求是由Web服务器自己发出的时候.
在我们的代码中是否会出现这种情况呢? 确实会出现,小菜使用定时器每隔1.5秒就引发了Elapsed事件.
处理代码是Timer_Elapsed-----间接就是--------m_configInfo = DeserializeInfo();
而DeserializeInfo()中又用到了ConfigFilePath所以,也就是说是应该使用老大说的代码...

可是小菜又想了,我刚才没有用老大的代码也一样正确的运行啊,这是什么原因呢?
因为第一次请求是来自Web的请求,为m_configFilePath赋值,它又是static类型,一直保存着,隔了1.5秒Timer_Elapsed中的代码被执行.使用到ConfigFilePath属性时,由于m_configFilePath不为null所以if(m_configFilePath!=null){/*这里不会被执行到了*/} 而是直接return m_configFilePath

所以说老大说的代码不是必须的......老大满意的点点头...

老大对小菜的工作感到挺满意.不过老大为了培养小菜,提出了更高的要求了.
小菜啊!你看你的代码,你每隔1.5秒,就取一次BaseConfigInfo.如果我一年没有修改这个DNT.config配置文件,你这一年时间内取了多少次BaeConfigInfo啊....小菜算了下,一年=365天=365*24小时=365*24*60分钟=365*24*60*60/1.5次
天呐,这数字真恐怖...

小菜赶紧跑回去修改代码了....小菜想到了解决方法了..通过System.IO.File.GetLastWriteTime(ConfigFilePath)
就可以得到最后修改文件的时间了,如果这个时间与新的最后修改文件的时间相同时,就表示该配置文件没有被修改..好,行动

using System;
using System.IO;
using System.Web;
using System.Xml.Serialization;

namespace Discuz.Config
{
    
/// <summary>
    
/// 基本配置文件管理类
    
/// </summary>

    public class BaseConfigFileManager
    
{
        
private static BaseConfigInfo m_configInfo; //基本配置信息描述对象
        private static string m_configFilePath; //基本配置文件路径
        private static System.Timers.Timer timer = new System.Timers.Timer(); //定时器
        private static DateTime m_fileOldChange; //基本配置文件最后修改时间

        
static BaseConfigFileManager()
        
{
            m_configInfo 
= LoadConfig(false);
            m_fileOldChange 
= File.GetLastWriteTime(ConfigFilePath);

            timer.Enabled 
= true//该值指示 Timer 是否应引发 Elapsed 事件 
            timer.Interval = 15000//获取或设置引发 Elapsed 事件的间隔 1.5秒
            timer.AutoReset = true//该值指示 Timer 是应在每次指定的间隔结束时引发 Elapsed 事件,还是仅在指定的间隔第一次结束后引发该事件
            timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
            timer.Start(); 
//通过将 Enabled 设置为 true 开始引发 Elapsed 事件
        }


        
/// <summary>
        
/// 每隔1.5秒重新加载基本配置描述信息
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>

        protected static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        
{
            LoadConfig(
true);
        }


        
/// <summary>
        
/// 加载(反序列化)基本配置信息描述对象
        
/// </summary>
        
/// <param name="checkTime">是否检查并更新传递进来的"文件加载时间"变量</param>
        
/// <returns></returns>

        protected static BaseConfigInfo LoadConfig(bool checkTime)
        
{
            
if (checkTime)
            
{
                DateTime m_fileNewChange 
= File.GetLastWriteTime(ConfigFilePath);
                
if (m_fileOldChange != m_fileNewChange)
                
{
                    m_fileOldChange 
= m_fileNewChange;

                    m_configInfo 
= DeserializeInfo();
                }

            }

            
else
            
{
                m_configInfo 
= DeserializeInfo();
            }


            
return m_configInfo;
        }


        
/// <summary>
        
/// 基本配置文件路径
        
/// </summary>

        private static string ConfigFilePath
        
{
            
get
            
{
                
if (m_configFilePath == null)
                
{
                    HttpContext context 
= HttpContext.Current;
                    m_configFilePath 
= context.Server.MapPath("~/DNT.config");
                }


                
return m_configFilePath;
            }

        }


        
/// <summary>
        
/// 返回基本配置信息描述对象
        
/// </summary>

        private static BaseConfigInfo GetBaseConfig
        
{
            
get
            
{
                
return m_configInfo;
            }

        }


        
/// <summary>
        
/// 返回数据库类型
        
/// </summary>

        public static string GetDbType
        
{
            
get
            
{
                
return GetBaseConfig.DbType;
            }

        }


        
/// <summary>
        
/// 反序列化基本配置信息描述类
        
/// </summary>
        
/// <returns></returns>

        private static BaseConfigInfo DeserializeInfo()
        
{
            BaseConfigInfo configInfo;
            FileStream fs 
= null;
            
try
            
{
                fs 
= new FileStream(ConfigFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                XmlSerializer serializer 
= new XmlSerializer(typeof(BaseConfigInfo));
                configInfo 
= (BaseConfigInfo)serializer.Deserialize(fs);
            }