posts - 283,  comments - 6275,  trackbacks - 107

    如果大家从官方下载2.0正式版的DLL程序集中会从里面找到discuz.config这个DLL文件。通过
reflector 反射加载这个程序集后,后从中找到一些从类名称上非常相似且有一定规律(格式)的类。
它们是:

    全局配置类
    GeneralConfigFileManager.cs
    GeneralConfigInfo.cs
    GeneralConfigs.cs

    Emial配置
    EmailConfigFileManager.cs
    EmailConfigInfo.cs
    EmailConfigs.cs

    基本配置类
    BaseConfigFileManager.cs
    BaseConfigInfo.cs
    BaseConfigInfoCollection.cs
    BaseConfigs.cs

    相册配置类
    AlbumConfigFileManager.cs
    AlbumConfigInfo.cs
    AlbumConfigs.cs

    聚合配置类
    AggregationConfig.cs
    AggregationConfigFileManager.cs
    AggregationConfigInfo.cs

    空间开通配置类
    SpaceActiveConfigs.cs
    SpaceActiveConfigFileManager.cs
    SpaceActiveConfigInfo.cs.cs

    可以看到,这些类基本上是以三个一组,共六组。而这六组类中的...FileManager.cs与Defau-
ltConfigFileManager.cs的关系如下图所示:


   


      从类图上看,DefaultConfigFileManager.cs是基类,而GeneralConfigFileManager.csEmai-
lConfigFileManager.cs
BaseConfigFileManager.csAlbumConfigFileManager.csAggregatio-
nConfigFileManager.cs
, SpaceActiveConfigFileManager.cs分别派生自DefaultConfigFileManager。
而DefaultConfigFileManager本身也定义了几个属性和方法以便于子类调用或重写(如SaveConfig)。
而DefaultConfigFileManager的定义如下:

   

  1 /// <summary>
  2    /// 文件配置管理基类
  3    /// </summary>

  4    public class DefaultConfigFileManager
  5    {
  6        /// <summary>
  7        /// 文件所在路径变量
  8        /// </summary>

  9        private static string m_configfilepath;
 10
 11        /// <summary>
 12        /// 临时配置对象变量
 13        /// </summary>

 14        private static IConfigInfo m_configinfo = null;
 15
 16        /// <summary>
 17        /// 锁对象
 18        /// </summary>

 19        private static object m_lockHelper = new object();
 20        
 21
 22        /// <summary>
 23        /// 文件所在路径
 24        /// </summary>

 25        public static string ConfigFilePath
 26        {
 27            get return m_configfilepath; }
 28            set { m_configfilepath = value; }
 29        }

 30
 31       
 32        /// <summary>
 33        /// 临时配置对象
 34        /// </summary>

 35        public static IConfigInfo ConfigInfo
 36        {
 37            get return m_configinfo; }
 38            set { m_configinfo = value; }
 39        }

 40             
 41        /// <summary>
 42        /// 加载(反序列化)指定对象类型的配置对象
 43        /// </summary>
 44        /// <param name="fileoldchange">文件加载时间</param>
 45        /// <param name="configFilePath">配置文件所在路径</param>
 46        /// <param name="configinfo">相应的变量 注:该参数主要用于设置m_configinfo变量和获取类型.GetType()</param>
 47        /// <returns></returns>

 48        protected static IConfigInfo LoadConfig(ref DateTime fileoldchange, string configFilePath, IConfigInfo configinfo)
 49        {
 50            return LoadConfig(ref fileoldchange, configFilePath, configinfo, true);
 51        }

 52
 53
 54        /// <summary>
 55        /// 加载(反序列化)指定对象类型的配置对象
 56        /// </summary>
 57        /// <param name="fileoldchange">文件加载时间</param>
 58        /// <param name="configFilePath">配置文件所在路径(包括文件名)</param>
 59        /// <param name="configinfo">相应的变量 注:该参数主要用于设置m_configinfo变量 和 获取类型.GetType()</param>
 60        /// <param name="checkTime">是否检查并更新传递进来的"文件加载时间"变量</param>
 61        /// <returns></returns>

 62        protected static IConfigInfo LoadConfig(ref DateTime fileoldchange, string configFilePath, IConfigInfo configinfo, bool checkTime)
 63        {
 64            m_configfilepath = configFilePath;
 65            m_configinfo = configinfo;
 66
 67            if (checkTime)
 68            {
 69                DateTime m_filenewchange = System.IO.File.GetLastWriteTime(configFilePath);
 70
 71                //当程序运行中config文件发生变化时则对config重新赋值
 72                if (fileoldchange != m_filenewchange)
 73                {
 74                    fileoldchange = m_filenewchange;
 75                    lock (m_lockHelper)
 76                    {
 77                        m_configinfo = DeserializeInfo(configFilePath, configinfo.GetType());
 78                    }

 79                }

 80            }

 81            else
 82            {
 83                lock (m_lockHelper)
 84                {
 85                    m_configinfo = DeserializeInfo(configFilePath, configinfo.GetType());
 86                }

 87                
 88            }

 89        
 90
 91            return m_configinfo;
 92        }

 93
 94
 95        /// <summary>
 96        /// 反序列化指定的类
 97        /// </summary>
 98        /// <param name="configfilepath">config 文件的路径</param>
 99        /// <param name="configtype">相应的类型</param>
100        /// <returns></returns>

101        public static IConfigInfo DeserializeInfo(string configfilepath, Type configtype)
102        {
103
104            IConfigInfo iconfiginfo;
105            FileStream fs = null;
106            try
107            {
108                fs = new FileStream(configfilepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
109                XmlSerializer serializer = new XmlSerializer(configtype);
110                iconfiginfo = (IConfigInfo)serializer.Deserialize(fs);
111            }

112            catch (Exception ex)
113            {
114                throw ex;
115            }

116            finally
117            {
118                if (fs != null)
119                {
120                    fs.Close();
121                }

122            }

123
124            return iconfiginfo;
125        }

126
127
128        public virtual bool SaveConfig()
129        {
130            return true;
131        }

132
133        /// <summary>
134        /// 保存(序列化)指定路径下的配置文件
135        /// </summary>
136        /// <param name="configFilePath">指定的配置文件所在的路径(包括文件名)</param>
137        /// <param name="configinfo">被保存(序列化)的对象</param>
138        /// <returns></returns>

139        public bool SaveConfig(string configFilePath, IConfigInfo configinfo)
140        {
141            bool succeed = false;
142            FileStream fs = null;
143            try
144            {
145                fs = new FileStream(configFilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
146                XmlSerializer serializer = new XmlSerializer(configinfo.GetType());
147                serializer.Serialize(fs, configinfo);
148                //成功则将会返回true
149                succeed = true;
150            }

151            catch (Exception ex)
152            {
153                throw ex;
154            }

155            finally
156            {
157                if (fs != null)
158                {
159                    fs.Close();
160                }

161            }

162
163            return succeed;
164        }

165    }

166
167


    如果您一直关注我们的这个产品,就会从中发现在1.0正式版时,这些类(或实现这些功能的类)
还是零星分面在discuz.forum和discuz.forumpage(2.0正式版改名为discuz.web.dll)等几个DLL文件
中。后来因为考虑软件架构和出于统一配置管理的需求,产品小组将这些类重构到了discuz.config,
从此这些类有了一个“新家”。

    为了便于开发和统一接口调用,我们又创建了两个接口类,就是IConfigFileManager.cs,ICon-
figInfo.cs,它们的声明如下(相关说明见注释):

    IConfigFileManager.cs

    

 1/// <summary>
 2    /// Discuz!NT 配置管理类接口
 3    /// </summary>

 4    public interface IConfigFileManager
 5    {
 6        /// <summary>
 7        /// 加载配置文件
 8        /// </summary>
 9        /// <returns></returns>

10        IConfigInfo LoadConfig();
11
12
13        /// <summary>
14        /// 保存配置文件
15        /// </summary>
16        /// <returns></returns>

17        bool SaveConfig();
18    }

19
20

    IConfigInfo.cs

   

1 /// <summary>
2    /// Discuz!NT 配置信息类接口
3    /// </summary>

4    public interface IConfigInfo
5    {
6    }

7

    大家可以看到,其中的 IConfigInfo接口没有任何属性和方法,是一个“空接口”,这主要是为
了提供统一的向上转型需要。当然,如果以后有需要还是会添加一些方法和属性的。
 
    为了减少篇幅,下面只对其中的 GeneralConfig进行相应介绍,一是因为它是核心的配置类,有
关它的使用在项目中不胜枚举。另外它也是这个项目中比较标准的“宝贝”,从一开始,只要有新的
功能往往都会对这个配置类有所“关照”。下面就是通过反射后得到的代码,相关的说明见注释即可:


    论坛全局配置管理类(GeneralConfigFileManager):

    

 1/// <summary>
 2    /// 全局配置设置管理类
 3    /// </summary>

 4    class GeneralConfigFileManager : Discuz.Config.DefaultConfigFileManager
 5    {
 6        private static GeneralConfigInfo m_configinfo;
 7
 8      
 9        /// <summary>
10        /// 文件修改时间
11        /// </summary>

12        private static DateTime m_fileoldchange;
13
14
15        /// <summary>
16        /// 初始化文件修改时间和对象实例
17        /// </summary>

18        static GeneralConfigFileManager()
19        {
20            m_fileoldchange = System.IO.File.GetLastWriteTime(ConfigFilePath);
21
22            try
23            {
24                m_configinfo = (GeneralConfigInfo)DefaultConfigFileManager.DeserializeInfo(ConfigFilePath, typeof(GeneralConfigInfo));
25            }

26            catch
27            {
28                if (File.Exists(ConfigFilePath))
29                {
30                    ReviseConfig();
31                    m_configinfo = (GeneralConfigInfo)DefaultConfigFileManager.DeserializeInfo(ConfigFilePath, typeof(GeneralConfigInfo));
32                }

33            }

34        }

35
36        public new static IConfigInfo ConfigInfo
37        {
38            get return m_configinfo; }
39            set { m_configinfo = (GeneralConfigInfo) value; }
40        }

41
42        /// <summary>
43        /// 配置文件所在路径
44        /// </summary>

45        public static string filename = null;
46
47
48        /// <summary>
49        /// 获取配置文件所在路径
50        /// </summary>

51        public new static string ConfigFilePath
52        {
53            get
54            {
55                if (filename == null)
56                {
57                    filename = Utils.GetMapPath(BaseConfigs.GetForumPath + "config/general.config");
58                }

59
60                return filename;
61            }

62
63        }

64
65        /// <summary>
66        /// 返回配置类实例
67        /// </summary>
68        /// <returns></returns>

69        public static GeneralConfigInfo LoadConfig()
70        {
71
72            try
73            {
74                ConfigInfo = DefaultConfigFileManager.LoadConfig(ref m_fileoldchange, ConfigFilePath, ConfigInfo, true);
75            }

76            catch
77            {
78                ReviseConfig();
79                ConfigInfo = DefaultConfigFileManager.LoadConfig(ref m_fileoldchange, ConfigFilePath, ConfigInfo, true);
80            }

81            return  ConfigInfo as GeneralConfigInfo;
82        }

83
84        /// <summary>
85        /// 保存配置类实例
86        /// </summary>
87        /// <returns></returns>

88        public override bool SaveConfig()
89        {
90            return base.SaveConfig(ConfigFilePath, ConfigInfo);
91        }

92
93


 论坛全局配置描述类(GeneralConfigInfo):

 

Code


 论坛全局配置类(GeneralConfigs):

 

  1 /// <summary>
  2 /// 论坛全局配置类
  3 /// </summary>

  4 public class GeneralConfigs
  5 {
  6  private static object lockHelper = new object();
  7
  8         private static System.Timers.Timer generalConfigTimer = new System.Timers.Timer(15000);
  9
 10         private static GeneralConfigInfo m_configinfo;
 11
 12         /// <summary>
 13         /// 静态构造函数初始化相应实例和定时器
 14         /// </summary>

 15         static GeneralConfigs()
 16         {
 17             m_configinfo = GeneralConfigFileManager.LoadConfig();
 18
 19             generalConfigTimer.AutoReset = true;
 20             generalConfigTimer.Enabled = true;
 21             generalConfigTimer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
 22             generalConfigTimer.Start();
 23         }

 24
 25         private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
 26         {
 27             ResetConfig();
 28         }

 29
 30
 31         /// <summary>
 32         /// 重设配置类实例
 33         /// </summary>

 34         public static void ResetConfig()
 35         {
 36             m_configinfo = GeneralConfigFileManager.LoadConfig();
 37         }

 38
 39  public static GeneralConfigInfo GetConfig()
 40  {
 41             return m_configinfo;
 42    }

 43
 44        
 45
 46  /// <summary>
 47  /// 获取默认模板id
 48  /// </summary>
 49  /// <returns></returns>

 50  public static int GetDefaultTemplateID()
 51  {
 52              return GetConfig().Templateid;
 53      }

 54
 55 
 56
 57  /// <summary>
 58  /// 获得设置项信息
 59  /// </summary>
 60  /// <returns>设置项</returns>

 61  public static bool SetIpDenyAccess(string denyipaccess)
 62  {
 63   bool result;
 64   
 65   lock(lockHelper) 
 66   {
 67    try
 68    {
 69                    GeneralConfigInfo configInfo = GeneralConfigs.GetConfig();
 70     configInfo.Ipdenyaccess = configInfo.Ipdenyaccess + "\n" + denyipaccess;
 71                    GeneralConfigs.Serialiaze(configInfo, Utils.GetMapPath(BaseConfigs.GetForumPath + "config/general.config"));
 72     result = true;
 73    }

 74    catch
 75    {
 76     return false;
 77    }

 78 
 79   }

 80   return result;
 81
 82  }

 83
 84
 85  Helper
108 }

109
110


    通过对general系列配置类的介绍,再看其它的配置类会很清楚了。这里就不再多做解释了,相信2.0开源后
大家看到源码和注释后会有所感悟的。

    另外就是之前因为用到了“序列化”,所以可能会出现所谓的“内存碎片”的问题,详见下面链接:

    而微软官方所推荐的方式如下(http://support.microsoft.com/kb/886385/en-us):

    1. Create one instance of the XmlSerializer class, and put that instance in the cache by using
       the caching APIs. For example, for a .dll file that is named HighSchool, the following code
       caches one instance of the XmlSerializer class
:

 

1  XmlSerializer mySerializer = new XmlSerializer(typeof(HighSchool.MyClass), attrOverrides, 
2      extraTypes, root, "http://www.microsoft.com");
3  Cache["HighSchoolSerializer"= mySerializer 

 

    2. Use the instance of the XmlSerializer class that you put in the cache instead of creating a
       new XmlSerializer object every time.
       Use the following XmlSerializer class constructors. These class constructors cache the
       assemblies
:

       In the .NET Framework version 1.0
       

1public XmlSerializer(Type);
2

       In the .NET Framework version 1.1
      

1  public XmlSerializer(Type type);
2        public XmlSerializer(Type type, string defaultNamespace); 
3 

 
    3. Declare the XmlSerializer object to be a static member of a class
    (这种方式是我们项目中所采用的方案)

     
     如果大家对这个话题感兴趣,恰恰园子里就有朋友做这方面的探索,链接如下:
     http://www.cnblogs.com/lixiong/archive/2007/10/26/938430.html

     好了,今天的内容到此就要结束了。希望大家能够支持和关注我们这个本土开源项目。祝大家工作顺利,
生活幸福,谢谢大家:)

    关键字:discuz,discuzNT,discuz.config,config,XmlSerializer,序列化,配置类,代震军,daizhj

  

posted on 2007-12-10 18:55 代震军 阅读(9584) 评论(59) 编辑 收藏

FeedBack:
2007-12-10 20:24 | 技术菜鸟      
Discuz!NT2.0还没开源,所以经常来楼主的博客上学习学习。
呵呵!楼主写的不错啊!造福我们这些菜鸟啦!

 回复 引用 查看   
2007-12-10 20:25 | sa1[未注册用户]
2.0什么时候开放源码啊?
而且现在好像没有全新安装文件似的

 回复 引用   
2007-12-10 20:33 | 笑疯^_^      
很不错
 回复 引用 查看   
2007-12-10 22:18 | vccc[未注册用户]
很不错呀,欢迎进入http://www.shi123.com交流啦
 回复 引用   
2007-12-10 22:19 | vccc[未注册用户]
如果再详细一点就好了,欢迎进入 http://www.shi123.com 交流已经心得
 回复 引用   
2007-12-11 09:09 | SummerySky[未注册用户]
请教一个问题,为什么DNT不从虚拟目录根目录读取dnt.config?
 回复 引用   
#7楼[楼主]
2007-12-11 09:16 | daizhj      
@SummerySky
主要是虚拟主机上的设置花样太多,就目前的方案,我个人认为还有一些瑕疵,而从应用程序目录(bin)作为标识去设置,倒能够兼容大多数虚拟主机(目录)的设置。当然,最终的解释还要看官方的。我只是谈谈我个人的观点而已。

 回复 引用 查看   
#8楼[楼主]
2007-12-11 09:17 | daizhj      
@技术菜鸟
过奖了,我个人认为:大家的关注和支持才是做好产品的保证。

 回复 引用 查看   
#9楼[楼主]
2007-12-11 09:21 | daizhj      
@sa1
对不起,这个问题我只能让您去关注官方的最新信息了:)请原谅。
我们目前的进度很正常,相信开源的日子不会太久了:)

 回复 引用 查看   
2007-12-11 10:19 | bisou[未注册用户]
终于有新文章了 ,自己看代码太累了 还是听课来的快
 回复 引用   
#11楼[楼主]
2007-12-11 13:19 | daizhj      
呵呵:)
 回复 引用 查看   
2007-12-11 16:38 | holygrace[未注册用户]
你好,能否在下次讲解一下discuz当前在线统计的设计思路!
 回复 引用   
#13楼[楼主]
2007-12-11 17:23 | daizhj      
@holygrace
您好,关于在线那块(包括统计功能)目前还不是介绍的"外围"重点,我会在下周的模板机制之后,考虑写一下这方面的资料,这也是关系着整合方案和二次开发所需要了解的.
同时感谢您对我们产品的关注:)

 回复 引用 查看   
2007-12-28 10:20 | 胡大壮      
请问代老师,配置类里那个BaseConfigInfoCollection是干什么用的?
 回复 引用 查看   
#15楼[楼主]
2007-12-28 13:31 | 代震军      
@胡大壮
BaseConfigInfoCollection是一个序列化集合类,当把BaseConfigInfo这样的实例对象放到集合类中再进行(反)序列化,就会出现形如下面这样的XML文件了:
〈?xml version="1.0"?〉
〈ArrayOfBaseConfigInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"〉
〈BaseConfigInfo〉
〈Dbconnectstring〉Data Source=10.0.0.1;User ID=sa;Password=;Initial Catalog=db1;Pooling=true〈/Dbconnectstring〉
〈Tableprefix〉dnt_〈/Tableprefix〉
〈Forumpath〉/〈/Forumpath〉
〈Dbtype〉SqlServer〈/Dbtype〉
〈Founderuid〉1〈/Founderuid〉
〈/BaseConfigInfo〉
〈BaseConfigInfo〉
〈Dbconnectstring〉Data Source=local;User ID=sa;Password=;Initial Catalog=db2;Pooling=true〈/Dbconnectstring〉
〈Tableprefix〉dnt_〈/Tableprefix〉
〈Forumpath〉/〈/Forumpath〉
〈Dbtype〉SqlServer〈/Dbtype〉
〈Founderuid〉1〈/Founderuid〉
〈/BaseConfigInfo〉
〈/ArrayOfBaseConfigInfo〉
而这样做的目的就是为了当安装多论坛时配置上可以用集合的方式进行管理.

 回复 引用 查看   
2007-12-28 14:57 | 胡大壮      
您所说的多论坛指的是什么,能实现多论坛共享用户群还是共享什么,刚才在nt.discuz.net搜索了一下似乎没有相关的文档,这块功能体现在什么地方呢?
 回复 引用 查看   
#17楼[楼主]
2007-12-29 10:08 | 代震军      
@胡大壮
当初的设计是想能过一个dnt.config文件来安装多个论坛,也就是在当前dnt.config配置下,有两上或多个论坛在不同的文件夹(或虚拟目录下)下运行,同时因为表前缀Tableprefix可以不同,所以可在同一数据库下安装几套论坛表和存储过程.
当前这块目前还有些小问题,所以未在文档中提过.相信将来会有所扩充的.

同时感谢您对我们产品的支持和关注:)

 回复 引用 查看   
2008-01-03 14:40 | Bryant      
看来我真的还很菜
呵呵
有个问题:我下载的源码,里面有乱码,编译不过去
咋整?

 回复 引用 查看   
#19楼[楼主]
2008-01-03 15:23 | 代震军      
@Bryant
在vs2005: "工具"--"选项"--->"文本编辑器"--->"常规" 右侧的"自动检测不带签名的utf-8编码"勾上,然后再打开先前出现乱码的页面,看看是否问题依旧。

 回复 引用 查看   
2008-01-08 22:27 | 拒绝潜水的鱼      
很好 很明了 利用了
 回复 引用 查看   
2008-01-22 17:01 | tcat[未注册用户]
支持
 回复 引用   
#22楼[楼主]
2008-01-22 17:29 | 代震军      
@tcat
感谢关注和支持:)

 回复 引用 查看   
2008-03-05 16:34 | 阿瑞--16hi      
麻烦问一下,这个架构图是使用什么软件制作的?
 回复 引用 查看   
#24楼[楼主]
2008-03-07 09:23 | 代震军      
@阿瑞--16hi
主要用的是VS2005中的类图功能

 回复 引用 查看   
2008-03-19 12:10 | cqs263[未注册用户]
好像没有地方用上接口IConfigFileManager,呵呵
 回复 引用   
#26楼[楼主]
2008-03-21 11:35 | 代震军      
@cqs263
这个接口主要是为了向上转型时使用,将来可能会用上(尽管眼下还未使用)。同时感谢您对我们产品的支持和关注:)

 回复 引用 查看   
2008-03-25 17:01 | 大眼镜[未注册用户]
说一下我的理解,这个配置模块是通过对IConfigInfo的实例类赋值后,序列化为xml文件保存到硬盘中,使用的时候,通过反序列化为对象,供其他程序使用.
不知道我的理解是否对.
配置数据使用频繁时,不断的反序列化,会不会影响性能呢

 回复 引用   
#28楼[楼主]
2008-03-25 17:22 | 代震军      
@大眼镜
您好,关于您的理解基本上是正确的,这也是我们事先所想实现的.
当然性能上我们因为使用了static,所以序列化的过程只在静态构造函数中实现.这样做的好处当然就是只运行一次,当下次再访问配置变量时,就不再进行反序列化了,您可以能过断点调试来验证这种行为:)

 回复 引用 查看   
2008-03-29 22:37 | 大眼镜[未注册用户]
谢谢楼主的回答
经过调试,确实只运行一次,为什么只运行一次还没有看明白,希望不吝赐教,还有一个问题请教楼主,假如配置实例对象不是一个,而是一个集合时,也就是说ConfigFilePath可以根据一定的规律变化时,有什么好解决方案呢?

 回复 引用   
#30楼[楼主]
2008-03-31 10:00 | 代震军      
@大眼镜
因为静态构造函数在程序首次运行时只加载一次,因为可以新一些配置信息或不经常变动的变量实例初始化在这里面,以确保下次访问变量时不再执行相同的代码,这主要是出于速度的考虑。
可以做集合对象的序列化比如:discuz.entity项目中的:OnlineUserInfoCollection.cs文件就是这相的集合化类,你可将它标识为序列化对象放在指定的可序列化的类中做为属性或直接序列化它本身,就可配置多个实例对象了。

 回复 引用 查看   
2008-04-12 17:21 | sealong[未注册用户]
楼主你好:
关于配置文件 GeneralConfigs 这个类中,添加了定时器,而根据我的观察,这个定时器根本没有启动,没有起到作用,没有起到作用为什么还有使用呢?

按照我的理解,其本意是定时刷新配置文件信息,但是这个作用却没有起到!请楼主赐教!!!谢谢!

 回复 引用   
#32楼[楼主]
2008-04-14 13:19 | 代震军      
@sealong
您可以能过设置断点的方式来看一下定时器所绑定的方法ResetConfig上,看看15秒后断点会不会再次执行到那里就可以了:)

 回复 引用 查看   
2008-05-13 14:41 | hjg[未注册用户]
ri
 回复 引用   
2008-06-09 11:06 | clefoo      
好啊,。。学习了。。DZ论坛真是太好了。。。永远支持
 回复 引用 查看   
#35楼[楼主]
2008-06-10 09:42 | 代震军      
@clefoo
多谢关注:)

 回复 引用 查看   
#36楼[楼主]
2008-06-10 09:42 | 代震军      
@hjg
???

 回复 引用 查看   
2008-07-18 17:10 | lesleyc[未注册用户]
老师你好,请问如果我要把discuz论坛跟项目独立开来配置,该怎么做呢?光修改forumpath好像不抵用。非常着急,谢谢。
 回复 引用   
#38楼[楼主]
2008-07-18 18:06 | 代震军      
@lesleyc
建议采用不同的虚拟目录方式配置论坛,和您的项目,然后再用链接传参的方式进行整合

 回复 引用 查看   
2008-10-31 15:44 | aaronshaohua[未注册用户]
我看了配置文件的源码有几个不明白的地方请教下:
1: public interface IConfigFileManager, 这个是“配置管理类接口”,我查了并没有类使用这个接口,设计他是为了开发和统一接口调用,但最终是因为什么原因而没用什么它?

2: 静态构造函数在类第一次被调用是会执行一次,且只会执行一次,这个是好处,但我觉得这个有个严重的问题,那就是如果在执行静态构造函数时出现异常,那将会有导致一些数据不会被初始化到。你对这个怎么理解? 比如:
static GeneralConfigFileManager()
{
m_configinfo = (GeneralConfigInfo)DefaultConfigFileManager.DeserializeInfo(ConfigFilePath, typeof(GeneralConfigInfo));

m_configpath = "D://test/conf.xml"; // 示例
}
如果在执行DeserializeInfo()这步反序列化时由于特殊原因出现异常. 那么你这个m_configinfo配置信息将不会被初始化,那么整个论坛都将报错. 而后面一句 m_configpath = "D://test/conf.xml"; 也不会被执行初始化.

3:对于你通过定时器来每15更新一次配置文件,我想你应该是仿照web.config来设计这个功能的。 但是
public static void ResetConfig()
{
m_configinfo = GeneralConfigFileManager.LoadConfig();
}
public static GeneralConfigInfo LoadConfig()
{
ConfigInfo = DefaultConfigFileManager.LoadConfig(ref m_fileoldchange, ConfigFilePath, ConfigInfo, true);
}
为什么DefaultConfigFileManager.LoadConfig()函数最后一个checkTime参数值要给"true"呢? 给"true"的话那么他会每隔15重新读取配置文件并加载.而你明显设计了通过判断文件最后更新时间来判断配置文件是否更新,从而再决定是否重新加载配置文件。 为什么不使用"false"呢?这样从效率来说更好.

 回复 引用   
2008-11-08 21:15 | 游客[未注册用户]
过度设计严重 貌似设计了接口和类 其实都是没什么实际意义的
用了大量的静态方法 还有静态类 似乎 回到的了函数调用的时代。。。

同意aaronshaohua [未注册用户]的意见 IConfigFileManager IConfigInfo 接口都没有使用的意思 所以才会出现空的接口

整个框架有可圈支取 详细作者研究了不少东西 但是代码级的东西 类的设计实在是。。。

期待下个版本的进步

 回复 引用   
#41楼[楼主]
2008-11-10 09:29 | 代震军      
@aaronshaohua
关于第一个问题其实目前没有直接使用,但不确保将来随着配置类框架的结构复杂化后要引用更加复杂的配置文件管理类,这时就需要抽象这个接口,以便于客户程序的统一调用了。所以这个类是眼下不用,将来可能会有用。所以被我们保留了。
另外您的第二个问题其实要具体场景具体分析了,因为您所说的前提是文件出现问题(如不存在或数据结构有问题)。但这块内容是在安装程序时即被配置好的,换句话说,如果站长他存心让自己的网站出问题,不按安装说明上传相应的配置文件的话。即使我们的程序写的再健壮又有什么用呢。还有就是这个文件的维护全部都是由管理员通过我们的程序来维护,而不是要他手工来做的(手工容易出错)。所以这样能很大程度上杜绝错误操作的发生。
还有就是你所说的checkTime参数的设置问题,其实应该是您还没完全看懂我们的程序逻辑,其注释上写的“是否检查并更新传递进来的"文件加载时间"变量”,而这个值是用于决定是否从文件中读取新对象,其程序结构如下:
if (checkTime)
{
DateTime m_filenewchange = System.IO.File.GetLastWriteTime(configFilePath);

//当程序运行中config文件发生变化时则对config重新赋值
if (fileoldchange != m_filenewchange)
{
fileoldchange = m_filenewchange;
lock (m_lockHelper)
{
m_configinfo = DeserializeInfo(configFilePath, configinfo.GetType());
}
}
}
请注意这个判断,即:if (fileoldchange != m_filenewchange)
只有文件操作时间发生变化才会重新读取,而如果使用FALSE,则会执行下面的逻辑:
else
{
lock (m_lockHelper)
{
m_configinfo = DeserializeInfo(configFilePath, configinfo.GetType());
}

}

这才是不管是否修改文件,直接从文件中读取数据的逻辑呀:)

 回复 引用 查看   
#42楼[楼主]
2008-11-10 09:46 | 代震军      
@游客
其实所谓的“过度设计严重 貌似设计了接口和类 其实都是没什么实际意义的”这句话,你可能并未真正理解什么叫过度设计,为了应对未来(很可能发生的)变化而提前使用接口,并未造成系统结构的难以理解和过度复杂(必定只是一个接口而已.另外就是过度设计主要是发生在了对“不确定因素不能正确评估”的基础上,导致自己主观臆测用户需求,而不是真正去评估量化,这样会很容易出现过度设计,这种现象的结果就是接口在项目中四处横行(不管是否存在变化风险,是否需要客户程序灵活响应,而直接全部使用接口).

“用了大量的静态方法 还有静态类”这里主要是出于性能考虑,这一点你可以看看微软的几个示例项目,里面有不少这方面的“信息”。而我们而的确得到了回报,首先是程序的运行速度,还有就是因为静态方法不用类实例即可使用(避免了声明类实例之后的维护和销毁)。这些都是好处。当然static同时也是因为这一点而被一些OO分子认为不OO的“罪魁”,但这并未影响其对面向对象语言的贡献,你可以看看"单体"模式就是要通过STATIC才会被实现出来。别外就是static为什么会被c++(好像是1987年的c++大会)接纳,就是因为其自己的优点被重视的结果。

所以切不可认为static就不好,总以一个OO分子自居,这样只能是作茧自缚了:)

 回复 引用 查看   
2009-01-22 14:52 | Cocohong[未注册用户]
好东西,跟博主学习...
 回复 引用   
2009-02-01 15:06 | 涂文瀚      
原来一直以为像定时后台运行的程序只有通过写客户端(Client)的方式来实现,看来博主对回复,自己设置断点测试,才晓得原来WEB方式的程序,也可以设定计时器(Timer)来定时运行代码,看Discuz!NT学到不少的东西,忠心希望博主继续撰写有关Discuz!NT的技术博客
 回复 引用 查看   
#45楼[楼主]
2009-02-02 09:31 | 代震军      
@涂文瀚
呵呵,不过还是要区别一下两种定时器的应用环境。

 回复 引用 查看   
2009-02-19 09:49 | feisky      
请问你的类图是用什么做的?
 回复 引用 查看   
#47楼[楼主]
2009-02-19 16:10 | 代震军      
@feisky
vs的类图工具

 回复 引用 查看   
2009-07-05 12:12 | benfeng      
请问使用了static之后.
在多个地方直接使用
GeneralConfigs.GetConfig().WebTitle
跟先定义一个generalConfig,然后多次调用generalConfig.WebTitle 在系统开销上面是一样的吗?

 回复 引用 查看   
#49楼[楼主]
2009-07-06 08:49 | 代震军      
@benfeng
一样

 回复 引用 查看   
2009-07-08 17:09 | skyaspnet      
您好,请问序列化是在服务器端进行操作的吗?为什么不采用直接读XML的方式吗? 使用序列化是不是多做了两步呢?

http://support.microsoft.com/kb/886385/en-us

还有您给的这个链接,感觉XML序列化很占内存,那么序列化的好处是什么呢?

谢谢!

 回复 引用 查看   
#51楼[楼主]
2009-07-08 17:20 | 代震军      
@skyaspnet
序列化出来的就是对象,而使用XML读取方法要使用XMLNODE的语法进行结点访问,无法返回对象属性的形式。所以在使用上还是有区别的。

 回复 引用 查看   
2009-07-09 00:29 | skyaspnet      
引用代震军:
@skyaspnet
序列化出来的就是对象,而使用XML读取方法要使用XMLNODE的语法进行结点访问,无法返回对象属性的形式。所以在使用上还是有区别的。

您好,没看懂这句话,返回的值有什么不同呢?可以举个简单的例子吗?谢谢!

 回复 引用 查看   
#53楼[楼主]
2009-07-09 08:11 | 代震军      
@skyaspnet
主要还是在返回类型的使用方式上的差异,比如使用序列化如下(代码参见Discuz.Config/BaseConfigFileManager.cs):
m_configinfo = (BaseConfigInfo) DefaultConfigFileManager.DeserializeInfo(ConfigFilePath, typeof(BaseConfigInfo));

上面的m_configinfo就是一个类BaseConfigInfo的实例,而该语句就是返序列化出来(从XML文件中序列化)的,你可以使用这种的格式“对象实例.属性”的方式来访问该对象的相关属性内容。

而使用xmlnode(读取xml并进于相应的结点访问的话),就要使用形如下面的代码来访问了(注意里面的n.Attributes["name"]这类的属性):
public static TemplateAboutInfo GetTemplateAboutInfo(string xmlPath)
{
TemplateAboutInfo aboutInfo = new TemplateAboutInfo();

///存放关于信息的文件 about.xml是否存在,不存在返回空串
if (!System.IO.File.Exists(xmlPath + @"\about.xml"))
return aboutInfo;

XmlDocument xml = new XmlDocument();

xml.Load(xmlPath + @"\about.xml");

try
{
XmlNode root = xml.SelectSingleNode("about");
foreach (XmlNode n in root.ChildNodes)
{
if (n.NodeType != XmlNodeType.Comment && n.Name.ToLower() == "template")
{
aboutInfo.name = n.Attributes["name"] != null ? n.Attributes["name"].Value.ToString() : "";
aboutInfo.author = n.Attributes["author"] != null ? n.Attributes["author"].Value.ToString() : "";
aboutInfo.createdate = n.Attributes["createdate"] != null ? n.Attributes["createdate"].Value.ToString() : "";
aboutInfo.ver = n.Attributes["ver"] != null ? n.Attributes["ver"].Value.ToString() : "";
aboutInfo.fordntver = n.Attributes["fordntver"] != null ? n.Attributes["fordntver"].Value.ToString() : "";
aboutInfo.copyright = n.Attributes["copyright"] != null ? n.Attributes["copyright"].Value.ToString() : "";
aboutInfo.width = n.Attributes["width"] != null ? n.Attributes["width"].Value.ToString() : "600";
}
}
}
catch
{
aboutInfo = new TemplateAboutInfo();
}
return aboutInfo;
}

所以我说的“Serializable”出来的是类,而使用XmlDocument 获取的只是一个xml文档实例,所以在属性访问上Serializable方式会更接近面向对象的方式。

 回复 引用 查看   
2009-07-09 22:01 | skyaspnet      
非常感谢您耐心的回复,还有些疑惑,就是DNT运行时先把配置文件序列化吗?序列化是把配置文件保存为例如 .dat这种文件吗?然后需要用时再反序列化?如果是这样的话那么如果配置文件发生了改变需要重新序列化再反序列化吗?那如何得知配置文件改动了呢?

如果不是我想的这样,那么是不是需要读取配置文件时直接先序列化XML,再反序列化它?

我是菜鸟,特别感谢您对我这些看着都让人烦的问题的耐心回答,真的很感激,谢谢!

 回复 引用 查看   
#55楼[楼主]
2009-07-10 09:26 | 代震军      
@skyaspnet
这里的序列化是指将对象信息保存到文件,而反序列化是将文件中的信息绑定初始化到相应对象实例。
我们的产品序列化保存的文件都是以.config结属的,你可以用记事本打开并浏览它。
另外我们的程序在启动是会把文件反序列化成对象实例,然后在程序中使用该对象的属性的。当文件发生变化的是我们在通过预先放置在相应的序列化类中的一个过期时间变量与文件修改时间进行比较,当两者不同时则视为修改,这时会告之程序需要重新获取实例对象。

 回复 引用 查看   
2011-04-20 18:44 | shenopkss      
代老大,看到这块有个疑问:
GeneralConfigs类的静态构造函数:
static GeneralConfigs()
{
m_configinfo = GeneralConfigFileManager.LoadConfig();


为什么不直接使用public new static IConfigInfo ConfigInfo 这个属性?

使用LoadConfig();不是多了一次序列化吗?

 回复 引用 查看   
#57楼[楼主]
2011-04-21 09:10 | 代震军      
@shenopkss
静态构造函数在程序运行期间只执行一次,这里这样做主要是为了封装调用方便。另外public new static IConfigInfo ConfigInfo只是属性获取和绑定操作,它自身不会进行序列化操作,所以要使用GeneralConfigFileManager.LoadConfig();

 回复 引用 查看   
2011-06-07 10:12 | 丨Style丨丶      
有个疑问呀
希望赐教
在DefaultConfigFileManager.cs里面的
protected static IConfigInfo LoadConfig(ref DateTime fileoldchange, string configFilePath, IConfigInfo configinfo, bool checkTime)
{
m_configfilepath = configFilePath;
m_configinfo = configinfo;

if (checkTime)
{
DateTime m_filenewchange = System.IO.File.GetLastWriteTime(configFilePath);

//当程序运行中config文件发生变化时则对config重新赋值
if (fileoldchange != m_filenewchange)
{
fileoldchange = m_filenewchange;
lock (m_lockHelper)
{
m_configinfo = DeserializeInfo(configFilePath, configinfo.GetType());
}
}
}
else
{
lock (m_lockHelper)
{
m_configinfo = DeserializeInfo(configFilePath, configinfo.GetType());
}

}
return m_configinfo;
}
不管是否检测修改时间 最后都是执行的 m_configinfo = DeserializeInfo(configFilePath, configinfo.GetType());这句话 中间除了个fileoldchange这个变量发生变化外 结果没任何变化
实在没看出来 这个检查 对结果有什么影响
BaseConfigFileManager.cs里面
/// <summary>
/// 加载配置类
/// </summary>
/// <returns></returns>
public static BaseConfigInfo LoadConfig()
{}
/// <summary>
/// 加载真正有效的配置类
/// </summary>
/// <returns></returns>
public static BaseConfigInfo LoadRealConfig()
{}
这两个似乎得到的结果是一样的 望老大赐教

 回复 引用 查看   
2011-06-07 11:01 | 丨Style丨丶      
明白了 如果修改时间没变的话 是不重新加载的
 回复 引用 查看   
昵称:代震军
园龄:5年11个月
荣誉:推荐博客
粉丝:492
关注:3

<2007年12月>
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

搜索

 
 

常用链接

随笔分类(366)

随笔档案(283)

文章分类(8)

文章档案(31)

相册

JavaScript

LINQ

silverlight

UML,OO

WebBlogger

负载开源项目

  • Discuz!NT
  • LLServer
  • TokyoTyrantClient
  • WebCam

个人简历

漫画

其它

企业级架构

网站案例研究

积分与排名

  • 积分 - 1217876
  • 排名 - 26

最新评论

阅读排行榜

评论排行榜

推荐排行榜