1. 配置节 ConfigSection

  private List<ConfigNode> _configNodes;

    public class ConfigNode
{
public ConfigNode()
{ } public ConfigNode(string key, string value)
{
Key = key;
Value = value;
} public string Key { get; set; }
public string Value { get; set; }
}

  可知,使用一个 key-value 型的链表结构来管理 基础配置。

  ConSection 里包含了对链表的操作:

public class ConfigSection
{
private List<ConfigNode> _configNodes;   //配置域管理一个配置链表
public int NodeCount { get { return _configNodes == null ? : _configNodes.Count; } } public void AddNode(ConfigNode node);   //加载一个配置节点
public ConfigNode GetNode(string key);   //获取“key”对应的配置节点
public bool SetValue(string key, string value);  //为“key”对应的节点设置“value”
public bool RemoveKey(string key);       //删除“key”对应的配置节点
public void Load(string nodeString);       //批量加载“key=value;key=value”格式的配置节点
}

  

  连接配置节:最重要的是增加了对“目标连接”的管理。

public class ConnectionSection : ConfigSection
{
public string Name { get; set; }
public string ProviderName { get; set; }
public string ConnectionString { get; set; } public ConnectionSection(string name, string providerName, string connectionString)
{
Load(name, providerName, connectionString);
} public void Load(string name, string providerName, string connectionString)
{
Name = name;
ProviderName = providerName;
ConnectionString = connectionString;
}
}

2.  配置的抽象

public interface IConfigger : IDisposable
{
void Install(); //加载配置
void Reload(); //重载配置
T GetFirstConfig<T>() where T : ConfigSection; //获取首个配置
T GetFirstOrAddConfig<T>() where T : ConfigSection, new(); //获取首个配置, 如果没有则初始化
IList<ConfigSection> GetAllConfig();
T GetConnetion<T>(string name) where T : ConnectionSection;
}

  

  数据配置:首先数据配置域管理了配置节的集合

private readonly List<ConfigSection> _dataList = new List<ConfigSection>();

public IList<T> GetConfig<T>() where T : ConfigSection
{
lock (_dataList)
{
return _dataList.OfType<T>().ToList(); //在集合中筛选出指定类型的集合
}
} /* 针对 _dataList 的增删改查 */
protected virtual void DoClearData();
public IList<ConfigSection> GetAllConfig();
protected void AddNodeData(ConfigSection nodeData);
protected virtual void DoClearData()

  下面来看更重要的几个变量与功能:

private FileSystemWatcher _watcher;
private HashSet<string> _changedFiles = new HashSet<string>();
private Timer _excuteTimer;
        protected virtual void InitDependenceFile()
{
_excuteTimer = new Timer(OnExcute, null, Timeout.Infinite, Timeout.Infinite);
string path = Path.GetDirectoryName(ConfigFile) ?? "";
if (!Directory.Exists(path))
{
return;
}
string file = Path.GetFileName(ConfigFile) ?? "*.config";
_watcher = new FileSystemWatcher(path, file);              //对配置文件的目录与文件进行监控
_watcher.Changed += new FileSystemEventHandler(OnWatcherChanged); //文件创建、修改、删除都会触发 “文件修改事件”
_watcher.Created += new FileSystemEventHandler(OnWatcherChanged);
_watcher.Deleted += new FileSystemEventHandler(OnWatcherChanged);
_watcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.Size;
_watcher.IncludeSubdirectories = false;                  //是否级联监视指定路径的子目录--否
_watcher.EnableRaisingEvents = true;                    //是否开启监控--是
IsDependenced = true;
}

  开启配置文件监控,注册监控事件,如果配置文件发生改变,则触发事件。

        public void Install()
{
if (!string.IsNullOrEmpty(ConfigFile) && File.Exists(ConfigFile))
{
InitDependenceFile();
}
LoadConfigData();
}

  启用该配置,则先开启配置文件监控,之后再装订配置数据。

  那么我们要关注的则是如何文件发生改变后做了什么事。

        private void OnWatcherChanged(object sender, FileSystemEventArgs e)
{
try
{
_changedFiles.Add(e.FullPath);
_excuteTimer.Change(_dueChangeTime, Timeout.Infinite); //过 _dueChangeTime 这段时间后重新启动定时器
}
catch (Exception ex)
{
TraceLog.WriteError("XmlDataConfigger changed error:{0}", ex);
}
}

  定时器的定时处理函数为:

        private void OnExcute(object state)
{
try
{
//Repetitive loading process
var tempFile = Interlocked.Exchange(ref _changedFiles, new HashSet<string>()); //以原子操作的形式将 _changedFiles 的值清空并返回 _changedFiles 的原始值 foreach (var fileName in tempFile)
{
var e = new ConfigChangedEventArgs() { FileName = fileName };
ConfigManager.OnConfigChanged(this, e); //由总配置管理器来发布该订阅--“该文件已发生改变”
Reload();
break; }
//stop timer
_excuteTimer.Change(Timeout.Infinite, Timeout.Infinite);
}
catch (Exception ex)
{
TraceLog.WriteError("XmlDataConfigger excute error:{0}", ex);
}
}
        public void Reload()
{
lock (_dataList)
{
DoClearData();
LoadConfigData(); //重新装订配置
}
TraceLog.WriteLine("{0} The configger has reloaded.", DateTime.Now.ToString("HH:mm:ss"));
var e = new ConfigReloadedEventArgs();
ConfigManager.OnConfigReloaded(this, e); //由总配置管理器来发布订阅--“该文件已重新加载”
}

  

  线索都集中到了 ConfigManager 的事件通知器了

ConfigManager.OnConfigChanged(this, e);
ConfigManager.OnConfigReloaded(this, e);  

  看来 ConfigManager 可以 对所管理的任意配置文件的修改 做出反馈

  另外还有重要的现象:

public string ConfigFile { get; set; }

  在 DataConfigger 里没有任何 API 对齐进行管理。

protected abstract void LoadConfigData();

  还有抽象接口并没有实现。

  也就意味着,DataConfigger 算是 配置抽象的基础封装, ConfigFile 与 LoadConfigData() 是留给其子类使用的,针对具体类型还会有具体的配置封装

  留下一个疑问,监控文件的为什么要用哈希表结构 HashSet<string> _changedFiles ?

  从 Scut 来看,它监控唯一的配置文件 GameServer.exe.config 就好了,但如果监控的是一系列文件(FileSystemWatcher 有这个能力),就可以通知 ConfigManager 具体是哪个文件修改了。

4. 配置域管理器

     private static HashSet<IConfigger> _configgerSet;         //ConfigManager 统一管理各配置
private static IConfigger _configger; public static T GetConfigger<T>() where T : IConfigger  //按配置类型 来检索获取 配置
{
return (T)GetConfigger(typeof(T));
} public static IConfigger GetConfigger(Type type)
{
lock (syncRoot)
{
foreach (IConfigger configger in _configgerSet)
{
if (configger.GetType() == type)
{
_configger = configger;
return configger;
}
} instance.Install(); //正如之前所分析, install 负责开启对配置文件的监控 与 该配置域的首次参数装订
_configgerSet.Add(instance);
_configger = instance;
return instance;
}
}

  

  除此之外,还有两个事件可以让使用者对文件修改做出监控反馈:

public static event EventHandler<ConfigChangedEventArgs> ConfigChanged;
public static event EventHandler<ConfigReloadedEventArgs> ConfigReloaded;

  

  从配置管理器也可以从 “App.config” 直接启动并生效整套配置:

        public static bool Intialize(string sectionName)
{
lock (syncRoot)
{
var section = ConfigurationManager.GetSection(sectionName); //在App.config中查到对应名称的配置
if (section is IConfigger)
{
var instance = section as IConfigger;
instance.Install(); //设置文件监控、首次装订参数
_configgerSet.Add(instance); //纳入配置管理器的管理
_configger = instance;
return true;
}
return false;
}
}

  插入一个与此关联的 Scut 的配置启动流程:

static EnvironmentSetting()     //可以同时有静态构造函数(类级别)与普通构造函数(实例级别)
{
bool result;
try
{
result = ConfigManager.Intialize("appServerConfigger");  //先从 app.config 中尝试加载配置 “appServerConfigger”
}
catch (Exception)
{
result = false;
}
if (!result) //配置文件加载失败则加载自带的默认配置
{
try
{
ConfigManager.GetConfigger<DefaultAppConfigger>();
}
catch (Exception ex)
{
TraceLog.WriteError("Configger init error:{0}", ex);
}
}
LoadDecodeFunc();
}

  由此我们可以控制 是否从外部配置文件启动

5. App.config 的使用封装 -- ConfigUtils  

public class ConfigUtils
{ public static NameValueCollection SettingsCollection
{
get
{
return ConfigurationManager.AppSettings;
}
} private ConfigUtils()
{
} public static int GetSetting(string key, int defaultValue)
{
int result = defaultValue;
try
{
object obj = SettingsCollection[key];
result = obj == null ? defaultValue : obj.ToInt();
}
catch { }
return result;
}
}

  

Scut:通用配置管理器的更多相关文章

  1. 一个简单的配置管理器(SettingManager)

    在很多.net开发的项目中,我们几乎都会使用到一些自定义的参数,比如说第三方的配置参数之类的. 他们的特点是:1.系统全局 2,可以做成键值对(Dictionary). 我们可以将这些参数放到Web. ...

  2. 【2016-10-27】【坚持学习】【Day14】【VS 配置管理器 AssemblyInfo 】

    有这样一个需求,不同客户,有不同的逻辑,通过配置管理器和条件编译进行 自动执行正确的代码.

  3. Win8、Win10进入SQL server配置管理器

    使用 WIN8.WIN10 访问 SQL Server 配置管理器 因为 SQL Server 配置管理器是 Microsoft 管理控制台程序的一个管理单元而不是单独的程序,所以,当运行 Windo ...

  4. 如何启动 SQL Server Agent(SQL Server 配置管理器)

    如何启动 SQL Server Agent(SQL Server 配置管理器) SQL Server 2008 R2 其他版本   4(共 6)对本文的评价是有帮助 - 评价此主题 可以从 SQL S ...

  5. Microsoft SQL Server,错误:2;SQL Server配置管理器(本地)—远程过程调用失败

    本机是先安装sqlserver2008,后安装vs2012 在安装sqlserver2008后,运行sqlserver2008正常,接着安装vs2012,再运行sqlserver2008,问题出现了, ...

  6. 将 SQL Server 实例设置为自动启动(SQL Server 配置管理器)

    本主题说明如何使用 SQL Server 配置管理器在 SQL Server 2012 中将 SQL Server 实例设置为自动启动. 在安装过程中,SQL Server 通常配置为自动启动. 如果 ...

  7. Windows10中“SQL Server 配置管理器”哪去了?

    SQL Server 配置管理器是一种工具,用于管理与 SQL Server 相关联的服务.配置 SQL Server 使用的网络协议以及从 SQL Server 客户端计算机管理网络连接配置.SQL ...

  8. python 通用装饰器,带有参数的装饰器,

    # 使用装饰器对有返回值的函数进行装饰# def func(functionName): # print('---func-1----') # def func_in(): # print(" ...

  9. 如果SQL Server 配置管理器没有找到就代表安装失败?

    如果SQL Server 配置管理器没有找到就代表安装失败? 2017-05-09 17:58 124人阅读 评论(0) 收藏 举报 版权声明:本文为博主原创文章,未经博主允许不得转载. 首先,只要你 ...

随机推荐

  1. angularJS服务一

    一 认识服务 1.服务这个概念其实并不陌生,在其他语言中如java便有这样的概念,其作用就是对外提供某个特定的功能,如消息服务,文件压缩服务等,是一个独立的模块.ng的服务是一个单例对象或函数,对外提 ...

  2. 融云的Java端实现

    产品中要使用融云实现即时通讯,下面是实现步骤: 1 .注册appkey secret,这个是第一步: 2 .下载融云Java客户端 https://github.com/rongcloud/serve ...

  3. 【sql进阶】SQL Server 将某一列的值拼接成字符串

    今天在统计报表的时候有这么一个需求,将一列字符串拼接成一行,然后展示到新的列中. 每一项的服务列表如下: 最终想要的结果是 sql如下: select AuxTypeName + ',' from ( ...

  4. 一个IT男的创业感言

    2014年的一月 我和高中的一个同学開始人生的第一次创业.就写点第一次创业的经验吧! 创业的最初 须要心中大概有个规划 这个规划可能是非常粗糙的 但大的方向一定要有.详细就是你进入的行业 行业已经存在 ...

  5. Zlib文件压缩和解压

    开源代码:http://www.zlib.net/zlib使用手册:http://www.zlib.net/manual.htmlzlib wince版:http://www.tenik.co.jp/ ...

  6. TwoSAT算法模板

    该模板来自大白书 [解释] 给多个语句,每个语句为“ Xi为真(假) 或者 Xj为真(假)” 每个变量和拆成两个点 2*i为假, 2*i+1为真 “Xi为真 或 Xj为真”  等价于 “Xi为假 –& ...

  7. vim中选择匹配文本删除技巧

    试举几例如下: 如何只保留匹配内容行而删除其他行? :v/pattern/d :help :v 如何对每行只保留匹配内容而删除这一行中的其它内容 :%s/^.pattern.$/\1/g 删除包含特定 ...

  8. python练习程序_员工信息表_基本实例

    python实现增删改查操作员工信息文件,可进行模糊查询: http://edu.51cto.com/lesson/id-13276.html http://edu.51cto.com/lesson/ ...

  9. oracle 的变量的定义和赋值

    第一种 :先定义后赋值 代码 : declare     V_AgeingType        varchar2(500); begin V_AgeingType :='111'; end 第二种 ...

  10. 织梦(dedecms)如何清空全部文章和删除后新增文章id号归1的方法

    很多朋友在使用织梦程序做网站的过程中,难免需要添加一些测试文章用于测试网站功能模板等,还有些人朋友网站改版需要变更内容的时候,面对着众多的老文章后总是一筹莫展! 由于织梦后台并不自带一键删除整站文章的 ...