博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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

Posted on 2008-07-15 13:51  a-peng  阅读(1012)  评论(9编辑  收藏  举报

话说小菜连打数个哈欠,趴在桌上就给睡着了.
开始又梦到Discuz!NT了.老大开始在骂小菜了,过了这么久还没有做好啊.赶快给我做好,不然炒了你,拿来配酒吃.

小菜不敢怠慢,连连说是.回到电脑前,伸伸懒腰,马上开工.
小菜先打开general.config通用配置文件看看究竟.


<?xml version="1.0"?>
<GeneralConfigInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  
<ForumTitle>Discuz!NT</ForumTitle>
  
<ForumUrl>forumindex.aspx</ForumUrl>
  
<Closed>0</Closed>
  
<CloseDreason>抱歉!论坛暂时关闭,稍后才能访问.</CloseDreason>
  
<RegStatus>1</RegStatus>
</GeneralConfigInfo>
后之前的DNT.config类似
1)都是XML文件
2)ForumTitle : 论坛名称
   ForumUrl : 论坛首页名称
   Closed : 论坛关闭 (0为开启 1为关闭)
   CloseDreason : 论坛关闭时提示信息
   RegStatus : 允许新用户注册 (0不允许 1允许)

按照之前的设计思路,小菜直接就想到了为其定义一个GeneralConfigInfo通用配置文件描述类
然后定义一个GeneralConfigFileManager通用配置文件管理类来管理它
using System;

namespace Discuz.Config
{
    
/// <summary>
    
/// 通用配置文件描述类 支持序列化与反序列化
    
/// </summary>

    [Serializable]
    
public class GeneralConfigInfo
    
{
        
private string m_forumTitle; //论坛名称
        private string m_forumUrl; //论坛URL地址
        private int m_closed; //论坛关闭 (0开 1关闭)
        private string m_closeDreason; //论坛关闭提示信息
        private int m_regStatus; //允许新用户注册 (0不允许 1允许)

        
/// <summary>
        
/// 论坛名称
        
/// </summary>

        public string ForumTitle
        
{
            
get
            
{
                
return m_forumTitle;
            }

            
set
            
{
                m_forumTitle 
= value;
            }

        }


        
/// <summary>
        
/// 论坛URL地址
        
/// </summary>

        public string ForumUrl
        
{
            
get
            
{
                
return m_forumUrl;
            }

            
set
            
{
                m_forumUrl 
= value;
            }

        }


        
/// <summary>
        
/// 论坛关闭 (0开 1关闭)
        
/// </summary>

        public int Closed
        
{
            
get
            
{
                
return m_closed;
            }

            
set
            
{
                m_closed 
= value;
            }

        }


        
/// <summary>
        
/// 论坛关闭提示信息
        
/// </summary>

        public string CloseDreason
        
{
            
get
            
{
                
return m_closeDreason;
            }

            
set
            
{
                m_closeDreason 
= value;
            }

        }


        
/// <summary>
        
/// 允许新用户注册 (0不允许 1允许)
        
/// </summary>

        public int RegStatus
        
{
            
get
            
{
                
return m_regStatus;
            }

            
set
            
{
                m_regStatus 
= value;
            }

        }

    }

}

接着定义GeneralConfigFileManager设计类似BaseConfigFileManager.
using System;
using System.IO;
using System.Web;
using System.Xml.Serialization;

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

    public class GeneralConfigFileManager
    
{
        
private static GeneralConfigInfo m_configInfo; //通用配置信息描述对象
        private static string m_configFileName = "general.config"//通用配置文件名称
        private static string m_configDirectory; //通用配置文件所在目录
        private static string m_configFilePath; //通用配置文件路径
        private static FileSystemWatcher watcher; //文件监测者

        
static GeneralConfigFileManager()
        
{
            m_configInfo 
= DeserializeInfo();

            watcher 
= new FileSystemWatcher();
            watcher.NotifyFilter 
= NotifyFilters.LastWrite; //监测上一次向文件写入内容的日期
            watcher.Path = ConfigDirectory; //监测目录
            watcher.Filter = m_configFileName; //监测文件
            watcher.Changed += new FileSystemEventHandler(OnChanged);//监测文件被修改时委托调用OnChanged
            watcher.EnableRaisingEvents = true//开始监测
        }


        
/// <summary>
        
/// 通用配置文件所在目录
        
/// </summary>

        private static string ConfigDirectory
        
{
            
get
            
{
                
if (m_configDirectory == null)
                
{
                    m_configDirectory 
= ConfigFilePath.Substring(0, ConfigFilePath.LastIndexOf('\\'));
                }


                
return m_configDirectory;
            }

        }


        
/// <summary>
        
/// 通用配置文件路径
        
/// </summary>

        private static string ConfigFilePath
        
{
            
get
            
{
                
if (m_configFilePath == null)
                
{
                    HttpContext current 
= HttpContext.Current;
                    m_configFilePath 
= current.Server.MapPath("~/config/" + m_configFileName);

                    
if (!File.Exists(m_configFilePath))
                    
{
                        
throw new Exception("发生错误: 网站config目录中没有正确的general.config文件");
                    }

                }


                
return m_configFilePath;
            }

        }


        
/// <summary>
        
/// 返回论坛名称
        
/// </summary>

        public static string GetForumTitle
        
{
            
get
            
{
                
return m_configInfo.ForumTitle;
            }

        }


        
/// <summary>
        
/// 监测文件被修改时委托调用OnChanged
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>

        protected static void OnChanged(object sender, FileSystemEventArgs e)
        
{
            m_configInfo 
= DeserializeInfo();
        }


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

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

            
catch (Exception ex)
            
{
                
throw ex;
            }

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


            
return configInfo;
        }

    }

}

测试Response.Write(Discuz.Config.GeneralConfigFileManager.GetForumTitle);
输出: Discuz!NT
将general.config配置文件中的<ForumTitle>Discuz!NT</ForumTitle>结点的值修改为 小菜论坛
刷新,立马看到 小菜论坛

接下来还有urls.config ,spread.config等等一大堆,Ctrl+C,Ctrl+V可不是好主意,因为重复的代码太多了.
虽然小菜有点菜,但是小菜立志向上发展.所以坚决不做代码工人.
小菜要做工匠.所以觉得应该第二次重构下代码
前一次重构是在 小菜梦游Discuz!NT (第三篇 配置文件处理2)  修理代码.BaseConfigFileManager

重构: BaseConfigFileManager与GeneralConfigFileManager代码重复太多,接下来还有UrlsConfigFileManager重复将更多.所以小菜决定为他们定义一个基类DefaultConfigFileManager
    1)DeserializeInfo()函数首当其冲,几乎完全一样.要想改造它,除非BaseConfigInfo与GeneralConfigInfo有共同的基类
       或接口,小菜决定定义一个空接口IConfigInfo然后让BaseConfigInfo与GeneralConfigInfo实现它.
using System;

namespace Discuz.Config
{
    
/// <summary>
    
/// 配置文件描述接口
    
/// </summary>

    public interface IConfigInfo
    
{
    }

}


using System;

namespace Discuz.Config
{
    
/// <summary>
    
/// 基本配置文件描述类 支持序列化与反序列化
    
/// </summary>

    [Serializable]
    
public class BaseConfigInfo : IConfigInfo
    
{
           省略
    }

}

using System;

namespace Discuz.Config
{
    
/// <summary>
    
/// 通用配置文件描述类 支持序列化与反序列化
    
/// </summary>

    [Serializable]
    
public class GeneralConfigInfo : IConfigInfo
    
{
         省略
    }

}

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

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

    public abstract class DefaultConfigFileManager
    
{
        
/// <summary>
        
/// 反序列化配置信息描述类
        
/// </summary>
        
/// <returns></returns>

        public static IConfigInfo DeserializeInfo(string configFilePath, Type configType)
        
{
            IConfigInfo configInfo;
            FileStream fs 
= null;
            
try
            
{
                fs 
= new FileStream(configFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                XmlSerializer serializer 
= new XmlSerializer(configType);
                configInfo 
= (IConfigInfo)serializer.Deserialize(fs);
            }

            
catch (Exception ex)
            
{
                
throw ex;
            }

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


            
return configInfo;
        }

    }

}

这样我们在派生类BaseConfigFileManager与GeneralConfigFileManager中只需将配置文件路径与序列化类型传给基类的DeserializeInfo(string configFilePath, Type configType)便可.

改造后的代码为
using System;
using System.IO;
using System.Web;
using System.Xml.Serialization;

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

    public class BaseConfigFileManager : DefaultConfigFileManager
    
{
        
private static BaseConfigInfo m_configInfo; //基本配置信息描述对象
        private static string m_configFileName = "DNT.config"//基本配置文件名称
        private static string m_configDirectory; //基本配置文件所在目录
        private static string m_configFilePath; //基本配置文件路径
        private static FileSystemWatcher watcher; //文件监测者

        
static BaseConfigFileManager()
        
{
            m_configInfo 
= (BaseConfigInfo)DefaultConfigFileManager.DeserializeInfo(ConfigFilePath, typeof(BaseConfigInfo));

            watcher 
= new FileSystemWatcher();
            watcher.NotifyFilter 
= NotifyFilters.LastWrite; //监测上一次向文件写入内容的日期
            watcher.Path = ConfigDirectory; //监测目录
            watcher.Filter = m_configFileName; //监测文件
            watcher.Changed += new FileSystemEventHandler(OnChanged);//监测文件被修改时委托调用OnChanged
            watcher.EnableRaisingEvents = true//开始监测
        }


        
/// <summary>
        
/// 基本配置文件所在目录
        
/// </summary>

        private static string ConfigDirectory
        
{
            
get
            
{
                
if (m_configDirectory == null)
                
{
                    m_configDirectory 
= ConfigFilePath.Substring(0, ConfigFilePath.LastIndexOf('\\'));
                }


                
return m_configDirectory;
            }

        }


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

        private static string ConfigFilePath
        
{
            
get
            
{
                
if (m_configFilePath == null)
                
{
                    HttpContext current 
= HttpContext.Current;
                    m_configFilePath 
= current.Server.MapPath("~/" + m_configFileName);
                }

                
                
if (!File.Exists(m_configFilePath))
                
{
                    
throw new Exception("发生错误: 网站根目录下没有正确的DNT.config文件");
                }


                
return m_configFilePath;
            }

        }


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

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

        }


        
/// <summary>
        
/// 论坛在站内的位置
        
/// </summary>

        public static string GetForumPath
        
{
            
get
            
{
                
return m_configInfo.ForumPath;
            }

        }


        
/// <summary>
        
/// 监测文件被修改时委托调用OnChanged
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>

        protected static void OnChanged(object sender, FileSystemEventArgs e)
        
{
            m_configInfo 
= (BaseConfigInfo)DefaultConfigFileManager.DeserializeInfo(ConfigFilePath, typeof(BaseConfigInfo));
        }

    }

}

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

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

    public class GeneralConfigFileManager : DefaultConfigFileManager
    
{
        
private static GeneralConfigInfo m_configInfo; //通用配置信息描述对象
        private static string m_configFileName = "general.config"//通用配置文件名称
        private static string m_configDirectory; //通用配置文件所在目录
        private static string m_configFilePath; //通用配置文件路径
        private static FileSystemWatcher watcher;

        
static GeneralConfigFileManager()
        
{
            m_configInfo 
= (GeneralConfigInfo)DefaultConfigFileManager.DeserializeInfo(ConfigFilePath, typeof(GeneralConfigInfo));

            watcher 
= new FileSystemWatcher();
            watcher.NotifyFilter 
= NotifyFilters.LastWrite; //监测上一次向文件写入内容的日期
            watcher.Path = ConfigDirectory; //监测目录
            watcher.Filter = m_configFileName; //监测文件
            watcher.Changed += new FileSystemEventHandler(OnChanged);//监测文件被修改时委托调用OnChanged
            watcher.EnableRaisingEvents = true//开始监测
        }


        
/// <summary>
        
/// 通用配置文件所在目录
        
/// </summary>

        private static string ConfigDirectory
        
{
            
get
            
{
                
if (m_configDirectory == null)
                
{
                    m_configDirectory 
= ConfigFilePath.Substring(0, ConfigFilePath.LastIndexOf('\\'));
                }


                
return m_configDirectory;
            }

        }


        
/// <summary>
        
/// 通用配置文件路径
        
/// </summary>

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


                
if (!File.Exists(m_configFilePath))
                
{
                    
throw new Exception("发生错误: 网站config目录下没有正确的general.config文件");
                }



                
return m_configFilePath;
            }

        }


        
/// <summary>
        
/// 返回论坛名称
        
/// </summary>

        public static string GetForumTitle
        
{
            
get
            
{
                
return m_configInfo.ForumTitle;
            }

        }


        
/// <summary>
        
/// 监测文件被修改时委托调用OnChanged
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>

        protected static void OnChanged(object sender, FileSystemEventArgs e)
        
{
            m_configInfo 
= (GeneralConfigInfo)DefaultConfigFileManager.DeserializeInfo(ConfigFilePath, typeof(GeneralConfigInfo));
        }

    }

}

小菜就这样构造出了EmailConfigFileManager等等配置文件的管理.....
代码给老大过目..
老大说:恩不错,不过还漏了一个功能啊.修改配置文件啊.
小菜说,为何要修改配置文件呢?可以直接打开配置文件修改了...
老大接着说:打开配置文件修改...噢,,天呐..这是一件多么麻烦的事...我们的用户可是会抱怨的...让他们对着那么多不知所云的配置文件.还要让他们修改....这几乎不太可能.

所以小菜啊,你得加上这个功能.我们的Web层小组会定制具有亲和力的界面来帮助用户方便的修改配置文件...

     这个界面怎么样,不错吧,,,比起直接修改配置文件要强很多吧...不过它们最终得依靠你提供的修改配置文件功能.

小菜听了老大这一番话后,马上回去修改代码..
毕竟小菜已经重构过代码了,现在添加功能已经容易很多.
在基类DefaultConfigFileManager中添加SaveConfig,派生类便可直接使用.
using System;
using System.IO;
using System.Xml.Serialization;

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

    public abstract class DefaultConfigFileManager
    
{
        其它略,同前面
        
/// <summary>
        
/// 保存(序列化)指定路径下的配置文件
        
/// </summary>
        
/// <param name="configFilePath">指定的配置文件所在的路径(包括文件名)</param>
        
/// <param name="configInfo">被保存(序列化)的对象</param>
        
/// <returns></returns>

        public static bool SaveConfig(string configFilePath, IConfigInfo configInfo)
        
{
            
bool succeed = false;
            FileStream fs 
= null;
            
try
            
{
                fs 
= new FileStream(configFilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
                XmlSerializer serializer 
= new XmlSerializer(configInfo.GetType());
                serializer.Serialize(fs, configInfo);
                
//成功则将会返回true
                succeed = true;
            }

            
catch (Exception ex)
            
{
                
throw ex;
            }

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

            }


            
return succeed;
        }

    }

}



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

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

    public class GeneralConfigFileManager : DefaultConfigFileManager
    
{
        其它略,同前面
        
public static bool SaveConfig(IConfigInfo configInfo)
        
{
            
bool success = false;
            
if (configInfo is GeneralConfigInfo)
            
{
                success 
= DefaultConfigFileManager.SaveConfig(ConfigFilePath, configInfo);
            }


            
return success;
        }

    }

}
BaseConfigFileManager当然也就和GeneralConfigFileManager类似了.
现在就让我们来测试一下.
我们修改打算修改general.config配置文件的论坛名称.从 Discuz!NT 修改为  小菜论坛 .
1)第一步.
先测试一下,论坛名称是什么.Response.Write("论坛名称:" + GeneralConfigFileManager.GetForumTitle);
输出:Discuz!NT
2)第二步.
修改论坛名称.

using System;
using Discuz.Config;

public partial class forumindex : System.Web.UI.Page
{
    
protected void Page_Load(object sender, EventArgs e)
    
{
        GeneralConfigInfo configInfo 
= new GeneralConfigInfo();
        configInfo.ForumTitle 
= "小菜论坛";
        configInfo.ForumUrl 
= "forumindex.aspx";
        configInfo.Closed 
= 0;
        configInfo.CloseDreason 
= "抱歉!论坛暂时关闭,稍后才能访问.";
        configInfo.RegStatus 
= 1;

        Response.Write(
"是否修改配置成功:" + GeneralConfigFileManager.SaveConfig(configInfo).ToString());
        Response.Write(
",论坛名称:" + GeneralConfigFileManager.GetForumTitle);
    }

}


程序输出:是否修改配置成功:True,论坛名称:Discuz!NT
奇怪了.修改成功.论坛名字为什么还是Discuz!NT而不是小菜论坛
到general.config中看一下

已经修改过来了,而且是还很正常.为小菜论坛 .

而且程序抛出了异常(XML文档0,0中有错误.奇怪了.general.config明明很正常)...这是为什么呢?


小菜决定把这个异常注释掉看看程序是否会照常运行.
//throw ex;
把general.config中的论坛名称重新改为Discuz!NT
运行.
程序输出:是否修改配置成功:True,论坛名称:Discuz!NT
刷新后
程序输出:是否修改配置成功:True,论坛名称:小菜论坛
一切正常.....小菜也不知道那个异常到底是为什么?希望高人指点.

这里谢谢@zahota : 小菜将DefaultConfigFileManager中的SaveConfig方法中的
fs = new FileStream(configFilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
修改为
fs = new FileStream(configFilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
就没有问题了,可以把上面的 //throw ex; 注释放心的去掉了.

原因是小菜也说不清楚,还是不说好,大家可以看下SDK2.0

快接近尾声了.
让我们来看看还有哪些不足.
很明显,我们修改论坛名时的代码
GeneralConfigInfo configInfo = new GeneralConfigInfo();
configInfo.ForumTitle = "小菜论坛";
configInfo.ForumUrl = "forumindex.aspx"; //我们不想要
configInfo.Closed = 0; //我们不想要
configInfo.CloseDreason = "抱歉!论坛暂时关闭,稍后才能访问."; //我们不想要
configInfo.RegStatus = 1; //我们不想要

除了一二两句,其它我们并不想要.因为我们只是想修改论坛名称而已.
但是不要又会出错,因为序列化的XML文件不完整.
怎么办呢?很简单.在GeneralConfigInfo代码中.为私有成员初始化便可.

using System;

namespace Discuz.Config
{
    
/// <summary>
    
/// 通用配置文件描述类 支持序列化与反序列化
    
/// </summary>

    [Serializable]
    
public class GeneralConfigInfo : IConfigInfo
    
{
        
private string m_forumTitle = "Discuz!NT"//论坛名称
        private string m_forumUrl = "forumindex.aspx"//论坛URL地址
        private int m_closed = 0//论坛关闭 (0开 1关闭)
        private string m_closeDreason = ""//论坛关闭提示信息
        private int m_regStatus = 1//允许新用户注册 (0不允许 1允许)

        
/// <summary>
        
/// 论坛名称
        
/// </summary>

        public string ForumTitle
        
{
            
get
            
{
                
return m_forumTitle;
            }

            
set
            
{
                m_forumTitle 
= value;
            }

        }


        
/// <summary>
        
/// 论坛URL地址
        
/// </summary>

        public string ForumUrl
        
{
            
get
            
{
                
return m_forumUrl;
            }

            
set
            
{
                m_forumUrl 
= value;
            }

        }


        
/// <summary>
        
/// 论坛关闭 (0开 1关闭)
        
/// </summary>

        public int Closed
        
{
            
get
            
{
                
return m_closed;
            }

            
set
            
{
                m_closed 
= value;
            }

        }


        
/// <summary>
        
/// 论坛关闭提示信息
        
/// </summary>

        public string CloseDreason
        
{
            
get
            
{
                
return m_closeDreason;
            }

            
set
            
{
                m_closeDreason 
= value;
            }

        }


        
/// <summary>
        
/// 允许新用户注册 (0不允许 1允许)
        
/// </summary>

        public int RegStatus
        
{
            
get
            
{
                
return m_regStatus;
            }

            
set
            
{
                m_regStatus 
= value;
            }

        }

    }

}
好了,这到这里,,,休息...休息

小菜梦游Discuz!NT配置文件处理部份完成,源代码:https://files.cnblogs.com/a-peng/newbie_config.rar