当前位置: 首页 > news >正文

Enterprise Library Step By Step系列(十五):配置应用程序块——设计篇

Enterprise Library Step By Step系列(十五):配置应用程序块——设计篇
Terrylee 2005 12 05
概述
配置应用程序块为应用系统提供了一个通用的配置管理解决方案,可以方便的从各种存储中读取配置信息。在设计上旨在提供一个用于读 / 写配置数据的简单接口,实现配置数据的读写与数据的存储相分离。使用 Storage Provider   Transformers 在应用和物理存储之间传递数据,同时采用抽象 AbstractFactory 模式生成 Provider 数据。先解释一下配置应用程序块中用到的两个重要的概念:
Storage Provider 是读写某个物理存储的对象,比如 XML 文件或 SQL 数据库
Transformers 是在存储格式和应用格式之间转换配置数据的对象
 
结构设计
下图展示了组成配置应用程序块的类和对象之间的关系。该图假定您使用  XML  文件存储提供程序和转换器,它们包含在应用程序块中。 XML  文件存储提供程序以文件的形式存储配置数据。(其他提供程序使用其他形式的存储,例如  Windows  注册表。) XmlFileStorageProvider   对象指向一个包含特定配置节的配置设置的文件。 ConfigurationBuilder 对象指向一个包含特定配置节的配置元数据的文件。通常,包含配置元数据的文件名为  App.config (对于基于  Windows  的应用程序)或  Web.config (对于基于  Web  的应用程序)。
 
配置应用程序块将配置元数据和实际的配置设置分隔开来。应用程序块将元数据放在它自己的文件中,而该文件独立于存储配置设置的位置。配置设置经过分组并称为配置节。应用程序使用的每个企业程序库应用程序块都有其自己的配置节,该配置节存储在其自己的文件中。配置应用程序块使用配置元数据来访问配置中的数据。
元数据指向配置存储位置并包含一些信息,例如,配置应用程序块读 / 写配置数据所需的转换器和存储提供程序的类型。配置元数据文件被分成节。每一节都包含在配置存储位置读 / 写一组特定的配置设置所需的信息。下图展示了元数据和配置区之间的关系:
 
ConfigurationManager   类提供一个在所定义的存储位置读 / 写特定配置节的配置设置的静态外观(个人觉得是在这里运用了门面模式,不知道对不对?)。 ConfigurationManager   对象从应用程序域配置文件读取配置元数据,然后使用这些信息来读 / 写配置节信息。
ConfigurationManager   类的静态方法使用  ConfigurationBuilder   对象的实例。 ConfigurationBuilder   可创建文件存储提供程序和转换器对象。这些对象可管理配置数据和元数据。
IStorageProviderReader   接口定义了用于从存储位置读取配置信息的接口。 IStorageProviderWriter   接口实现了  IStorageProviderReader   接口,还定义了用于写入配置信息的接口。配置应用程序块包含一个支持该接口的提供程序  XmlFileStorageProvider ,它在一个  XML  文件中读 / 写配置数据。
ITransformer   接口可转换应用程序和存储提供程序之间的配置设置对象。配置应用程序块包含一个实现该接口的提供程序,即  XmlSerializerTransformer   类。 XmlSerializerTransformer   类实现了应用程序定义的运行时对象和  XmlNode   对象之间的转换,而无需应用程序来配置转换器。如果没有转换器,配置设置对象就会以存储提供程序提供的相同格式返回到应用程序。
每个配置节的设置都缓存在一个哈希表中。当客户端请求配置数据时, ConfigurationBuilder   对象会在缓存中查找数据。如果在缓存中找到配置数据, ConfigurationBuilder   对象就不必访问存储中的配置数据。如果文件存储提供程序检测到存储中的配置数据已经更改,则  ConfigurationBuilder   对象就会清除缓存。 ConfigurationManager   对象允许应用程序清除全部缓存,或者只清除给定节名的缓存。如果清除了缓存,则下一个读取操作就会访问存储位置中的配置设置。
 
解耦
这个词在配置应用程序块中得到了很好的体现,将配置数据的读写和配置数据的存储分离。在配置应用程序块中已经实现了读写 XML Storage Provider ,同时支持开发者根据数据存储的物理位置来编写相应的 Provider ,见下图:
 
如果我们编写了自己的 Storage Provider  Transformer ,那么我们可以很简单的利用配置工具来修改数据的存储而无须修改任何代码(这也是整个企业库的设计思想的体现,配置驱动)。
 
简化配置
配置应用程序块做到让开发人员通过一行代码来实现对配置数据的读取和写入,下面的代码展示了如何读取和写入配置数据:
1 ExpandedBlockStart.gif /// 读取配置数据
2 None.gif MyConfigClass configData  =  ConfigurationManager.GetConfiguration( " MySettings " as  MyConfigClass;
3 None.gif
4 ExpandedBlockStart.gif /// 写入配置数据
5 None.gif ConfigurationManager.WriteConfiguration( " MySettings " , configData);
而应用程序块在读写配置数据时,实际上是执行了 ConfigurationBuilder ReadConfiguration() WriteConfiguration() 方法。 ConfigurationManager 类通过外观模式把这个两个方法封装成了上面所写的 GetConfiguration() WriteConfiguration() 方法。
下面我们看一下具体的读写代码:
 1 None.gif public   object  ReadConfiguration( string  sectionName)
 2 ExpandedBlockStart.gif {    
 3ExpandedSubBlockStart.gif    ///验证有效性
 4InBlock.gif    ValidateSection(sectionName);
 5InBlock.gif    
 6ExpandedSubBlockStart.gif    ///变量configurationSection代表具体的配置数据类:MyConfigClass
 7InBlock.gif    object configurationSection = sections.GetSection(sectionName);
 8InBlock.gif    
 9ExpandedSubBlockStart.gif    ///缓存存在就直接返回结果
10InBlock.gif    if (IsConfigurationSectionCached(configurationSection))
11ExpandedSubBlockStart.gif    {
12InBlock.gif        return configurationSection;
13ExpandedSubBlockEnd.gif    }
14InBlock.gif    
15InBlock.gif    IStorageProviderReader storageProviderReader = CreateStorageProvider(sectionName);
16InBlock.gif    
17ExpandedSubBlockStart.gif    ///变量configurationSettings代表的是具体配置数据中的配置项物理格式的数据
18ExpandedSubBlockEnd.gif    ///核心功能,调用Read()方法,实际的读取由Provider完成
19InBlock.gif    object configurationSettings = storageProviderReader.Read();
20InBlock.gif    if (configurationSettings == null)
21ExpandedSubBlockStart.gif    {
22InBlock.gif        return null;
23ExpandedSubBlockEnd.gif    }
24InBlock.gif
25InBlock.gif    ITransformer transformer = CreateTransformer(sectionName);
26InBlock.gif    if (transformer != null)
27ExpandedSubBlockStart.gif    {
28ExpandedSubBlockStart.gif        ///将配置数据由代表物理格式配置数据的类转变为代表应用程序直接访问的配置类
29InBlock.gif        configurationSection = transformer.Deserialize(configurationSettings);
30ExpandedSubBlockEnd.gif    }
31InBlock.gif    else
32ExpandedSubBlockStart.gif    {
33InBlock.gif        configurationSection = configurationSettings;
34ExpandedSubBlockEnd.gif    }
35InBlock.gif
36InBlock.gif    ConfigurationChangedEventHandler changed = new ConfigurationChangedEventHandler(OnExternalConfigurationChanged);
37InBlock.gif    
38ExpandedSubBlockStart.gif    ///增加到缓存中
39InBlock.gif    sections.AddSection(sectionName, configurationSection, changed, storageProviderReader);
40InBlock.gif
41InBlock.gif    return configurationSection;
42ExpandedBlockEnd.gif}

 1 None.gif public   void  WriteConfiguration( string  sectionName,  object  configValue)
 2 ExpandedBlockStart.gif {    
 3ExpandedSubBlockStart.gif    ///验证有效性
 4InBlock.gif    ValidateSection(sectionName);
 5InBlock.gif    
 6ExpandedSubBlockStart.gif    ///注册写前事件
 7InBlock.gif    ConfigurationChangingEventArgs args = CreateConfigurationChangingEventArgs(sectionName, configValue);
 8InBlock.gif    OnConfigurationChanging(args);
 9InBlock.gif    if (!args.Cancel)
10ExpandedSubBlockStart.gif    {
11ExpandedSubBlockStart.gif        ///创建编写器
12InBlock.gif        IStorageProviderWriter configStorageWriter = GetConfigurationStorageWriter(sectionName);
13InBlock.gif        
14ExpandedSubBlockStart.gif        ///将要保存的值转换成Provider可识别的格式,具体何种格式是由配置元数据决定的
15InBlock.gif        object writeData = GetSerializedDataToWrite(sectionName, configValue);
16InBlock.gif        ConfigurationWriterActionCommand writerActionCommand = new ConfigurationWriterActionCommand(configStorageWriter, writeData);
17InBlock.gif        
18ExpandedSubBlockStart.gif        ///如果配置节尚不存在就添加此配置数据
19InBlock.gif        if (!sections.ContainsSection(sectionName))
20ExpandedSubBlockStart.gif        {
21InBlock.gif            AddSection(sectionName, configValue, configStorageWriter);
22ExpandedSubBlockEnd.gif        }
23InBlock.gif        
24ExpandedSubBlockStart.gif        ///如果配置节已存在就更新此配置数据
25InBlock.gif        sections.UpdateSection(sectionName, writerActionCommand, configValue);
26InBlock.gif        
27ExpandedSubBlockStart.gif        ///注册写完成事件
28InBlock.gif        ConfigurationChangedEventArgs changedArgs = new ConfigurationChangedEventArgs(configFile.FileName, sectionName);
29InBlock.gif        OnConfigurationChanged(changedArgs);
30ExpandedSubBlockEnd.gif    }
31ExpandedBlockEnd.gif}

扩展器和工厂
由于找不到更好的中文字来说明 Provider ,所以只好用了扩展器这个名字,大家见谅。来看一下配置应用程序块中的 Providers 结构图:
 
IConfigurationProvider   接口是所有的 Providers 必须实现的,以便配置应用程序块能够创建和初始化它们。该接口中有一个方法 Initialize() 和一个属性 ConfigurationName ,配置应用程序块调用 Initialize() 方法来创建每一个 Providers
配置应用程序块中包含了一个抽象的基类 ConfigurationProvider 。它实现了 IConfigurationProvider   接口中的 ConfigurationName 属性。
配置应用程序块中的 Factories 结构图:
 
ConfigurationFactory 是一个抽象的基类,它定义了应用程序块中所有的工厂类的接口,所有的 Factory 类必须从它继承。 ProviderFactory 类实现了 IConfigurationProvider 并从 ConfigurationFactory 类继承,也是一个抽象类。
 
总结
好了,这里引用 MSDN 上的一句话来结束这篇 Post ,“ 设计了配置应用程序块,您就可以用最适合应用程序要求的方式将配置数据存储在应用程序中,使您不受存储方法的限制 ”。











本文转自lihuijun51CTO博客,原文链接: http://blog.51cto.com/terrylee/67617  ,如需转载请自行联系原作者


相关文章:

  • JAVA 线程池之Callable返回结果
  • 用户系列之五:用户SID查看之终结版
  • SQLite第二课 源码下载编译
  • 查看Linux服务器网卡流量小脚本shell和Python各一例
  • 6.4 xz压缩工具
  • Memcached通用类(基于enyim.com Memcached Client)
  • PS如何批量生成缩略图(方法可以通用其他重复劳动)
  • .NET开源项目介绍及资源推荐:数据持久层
  • Wireshark网络抓包(二)——过滤器
  • Qt之JSON生成与解析1
  • command for cut
  • ubuntu 11.10下载和编译Android源码
  • 【移动开发】Android应用开发者应该知道的东西
  • Android开发之旅:组件生命周期(二)
  • LAMP 全功能编译安装 for CentOS6.3笔记(更新)
  • php的引用
  • 【5+】跨webview多页面 触发事件(二)
  • Android交互
  • Dubbo 整合 Pinpoint 做分布式服务请求跟踪
  • java8 Stream Pipelines 浅析
  • Java面向对象及其三大特征
  • MobX
  • puppeteer stop redirect 的正确姿势及 net::ERR_FAILED 的解决
  • rc-form之最单纯情况
  • windows-nginx-https-本地配置
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 漫谈开发设计中的一些“原则”及“设计哲学”
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 区块链将重新定义世界
  • 腾讯优测优分享 | Android碎片化问题小结——关于闪光灯的那些事儿
  • 跳前端坑前,先看看这个!!
  • 微服务框架lagom
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 我建了一个叫Hello World的项目
  • 硬币翻转问题,区间操作
  • 字符串匹配基础上
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • #QT(一种朴素的计算器实现方法)
  • $con= MySQL有关填空题_2015年计算机二级考试《MySQL》提高练习题(10)
  • ( 10 )MySQL中的外键
  • (1)Nginx简介和安装教程
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (Java实习生)每日10道面试题打卡——JavaWeb篇
  • (亲测成功)在centos7.5上安装kvm,通过VNC远程连接并创建多台ubuntu虚拟机(ubuntu server版本)...
  • (三)Honghu Cloud云架构一定时调度平台
  • (五)c52学习之旅-静态数码管
  • (一)为什么要选择C++
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • (转)linux下的时间函数使用
  • (转)用.Net的File控件上传文件的解决方案
  • *p=a是把a的值赋给p,p=a是把a的地址赋给p。
  • .net core 依赖注入的基本用发
  • .net和jar包windows服务部署