Enterprise Library Step By Step系列(二):配置应用程序块——进阶篇

 在前一篇文章中,讲述了配置应用程序块的最简单的介绍,在本篇文章中我主要介绍一下配置应用程序块的响应配置变更通知,保护配置信息(加密配置信息),面向高级人员的扩展机制,配置数据的缓存等几个方面。在剖析篇中我会去分析配置应用程序块的底层设计及类设计。

一.响应配置变更通知:

Configuration Application Block提供了一个事件机制,当存储的配置变更时通知应用程序 ,使用步骤:

1)创建一个EverntHandler

 1/// <summary>
 2        /// 创建EventHanler
 3        /// </summary>
 4        /// <param name="sender"></param>
 5        /// <param name="args"></param>

 6        private void OnConfigurationChanged(object sender, ConfigurationChangedEventArgs args)
 7        {
 8            Cursor = System.Windows.Forms.Cursors.WaitCursor;
 9
10            EditorFontData configData = ConfigurationManager.GetConfiguration("EditorSettings"as EditorFontData;
11
12            StringBuilder results = new StringBuilder();            
13            results.Append("Configuration changes in storage were detected. Updating configuration.");
14            results.Append(Environment.NewLine);
15            results.Append("New configuration settings:");
16            results.Append(Environment.NewLine);
17            results.Append('\t');
18            results.Append(configData.ToString());
19            results.Append(Environment.NewLine);
20
21            Cursor = System.Windows.Forms.Cursors.Arrow;      
22        }

2)注册事件

1///注册事件
2        ConfigurationManager.ConfigurationChanged += new ConfigurationChangedEventHandler(OnConfigurationChanged); 

二.配置数据的缓存:

Configuration Application Block在设计时提供了对配置数据的缓存,在读取XML数据后,再次读取它首先会判断缓存是否为空,如果不为空,它会直接从缓存中读取数据(在剖析篇中会有详细的介绍)。

显式的清除掉缓存用下面这句代码即可:

1///清除缓存数据
2         ConfigurationManager.ClearSingletonSectionCache();

三.面向高级人员的扩展机制:

1 除了用XML文件可以存储数据外,还可以创建自己的存储方式,像SQL Server Database,注册表存储等,这时就需要我们自己创建StorageProvider。创建自定义的Storage Provider,需要注意以下几点:

1)要读取和写入数据,需要继承于StorageProvider类和分别实现IStorageProviderReaderIstorageProviderWriter接口:

1public class XmlFileStorageProvider : StorageProvider, IStorageProviderWriter
2        {
3            //……
4        }

2)如果实现了IConfigurationProvider接口,则方法Initialize()就不能为空,也必须实现:

1public override void Initialize(ConfigurationView configurationView)
2        {
3            //……
4        }

3)实现Read()Write()方法,记住一定要返回类型为object,否则Transformer将无法使用:

1public override object Read()
2        {
3            //……
4        }

5
6        public void Write(object value)
7        {
8            //……
9        }

2.创建自定义的Transformer

如果我们创建的自定义的Storage Provider不能后支持XMLNode,这时候我们需要创建自己的Transformer,需要注意以下几点:

1)自定义的Transformer如果实现了Itransformer接口;则必须实现方法Serialize()Deserialize();

2)自定义的Transformer如果实现了IConfigurationProvider接口,则方法Initialize()就不能为空,也必须实现;

下面给出一个SoapSerializerTransformer的例子程序(先声名一下,这个例子程序不是我写的,而是Dario Fruk先生^_^):

 1namespace idroot.Framework.Configuration
 2{
 3    using System;
 4    using System.Configuration;
 5    using System.IO;
 6    using System.Runtime.Serialization.Formatters.Soap;
 7    using System.Text;
 8    using System.Xml;
 9
10    using Microsoft.Practices.EnterpriseLibrary.Common;
11    using Microsoft.Practices.EnterpriseLibrary.Configuration;
12
13    /// <summary>
14    /// SoapSerializerTransformer is a custom Serialization Transformer for Microsft Enterprise Library 1.0.
15    /// </summary>

16    public class SoapSerializerTransformer : TransformerProvider
17    
18        public override void Initialize(ConfigurationView configurationView)
19        {
20            // Do nothing. This implementation does not require any additional configuration data because SoapFormatter reflects types 
21            // during serialization.
22        }

23
24        public override object Serialize(object value)
25        {
26            SoapFormatter soapFormatter = new SoapFormatter();
27            StringBuilder stringBuilder = new StringBuilder();
28            XmlDocument doc = new XmlDocument();
29
30            stringBuilder.Append("<soapSerializerSection>");
31
32            string serializedObject = "";
33            using (MemoryStream stream = new MemoryStream())
34            {
35                soapFormatter.Serialize(stream, value);
36                byte[] buffer = stream.GetBuffer();
37                // quick fix for 0-byte padding
38                serializedObject = ASCIIEncoding.ASCII.GetString(buffer).Replace('\0'' ').Trim();
39            }

40            stringBuilder.Append(serializedObject);
41
42            stringBuilder.Append("</soapSerializerSection>");
43            doc.LoadXml(stringBuilder.ToString());
44
45            return doc.DocumentElement;
46        }

47
48        public override object Deserialize(object section)
49        {
50            ArgumentValidation.CheckForNullReference(section, "section");
51            ArgumentValidation.CheckExpectedType(section, typeof(XmlNode));
52
53            XmlNode sectionNode = (XmlNode)section;
54
55            XmlNode serializedObjectNode = sectionNode.SelectSingleNode("//soapSerializerSection");
56            if (serializedObjectNode == null)
57            {
58                throw new ConfigurationException("The required element '<soapSerializationSection>' missing in the specified Xml configuration file.");
59            }

60
61            SoapFormatter soapFormatter = new SoapFormatter();
62            try
63            {
64                object obj = null;
65                using (MemoryStream stream = new MemoryStream())
66                {
67                    using (StreamWriter sw = new StreamWriter(stream, Encoding.ASCII))
68                    {
69                        sw.Write(serializedObjectNode.InnerXml);
70                        sw.Flush();
71                        // rewind stream to the begining or deserialization will throw Exception.
72                        sw.BaseStream.Seek(0, SeekOrigin.Begin); 
73                        obj = soapFormatter.Deserialize(stream);
74                    }

75                }

76                return obj;
77            }

78            catch (InvalidOperationException e)
79            {
80                string message = e.Message;
81                if (null != e.InnerException)
82                {
83                    message = String.Concat(message, " ", e.InnerException.Message);
84                }

85                throw new ConfigurationException(message, e);
86            }

87        }

88    }

89}
 

3.使用其它的Providers

       SQL Server Provider:使用数据库SQL Server Provider

       Registry Provider:使用注册表Provider

四.保护配置信息:

配置信息直接放在了XML文件里面是不安全,我们可以用加密应用程序块对其进行加密,其实对于所有的应用程序块的配置信息都可以进行加密,我们到加密应用程序块时再详细讨论:)

进阶篇就写到这里了,后面继续剖析篇,在剖析篇里我会从配置应用程序块的底层设计,到类设计等作一些介绍(个人理解^_^

作者:TerryLee
出处:http://terrylee.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
posted @ 2005-10-15 12:21 TerryLee 阅读(13845) 评论(21) 编辑 收藏

 回复 引用   
#1楼 2005-11-29 14:15 autuwater[未注册用户]
这样的自定义的Transformer、或者扩展机制怎么使用?可以结合该库提供的控制台配置config么?
 回复 引用   
#2楼 2005-11-29 14:17 autuwater[未注册用户]
有谁使用过?斑竹Terrylee,你呢?我想使用这个SoapSerializerTransformer代替默认的XmlSerializerTransformerData,怎么使用?请赐教
 回复 引用 查看   
#3楼[楼主] 2005-11-29 14:47 Terrylee      
@autuwater

SoapSerializerTransformer使用的方法跟用默认的XmlSerializerTransformerData没有多大区别

不同之处在于你为配置区创建Transformer时创建一个Custom Transformer Provider,然后指定它的TypeName为SoapSerializerTransformer程序集

其他的步骤都不用变:)

 回复 引用   
#4楼 2005-12-01 14:15 autuwater[未注册用户]
谢谢!醍醐灌顶。

不过希望您能够使用Together这样的工具,产生UML,讲解其中的构架特性。


我们每人有一份快乐,相互交换每人就都拥有两份快乐,何乐而不为呢!^_^

 回复 引用 查看   
#5楼[楼主] 2005-12-01 16:53 Terrylee      
@autuwater

我以后尽力做到这一点:)

 回复 引用 查看   
#6楼 2005-12-04 18:09 黑马      
这个block的文件太多,看代码的话理不清他们之间的关系,能不能把关系图传上来?
我和autuwater的意思一样,谢谢啦!!

 回复 引用 查看   
#7楼 2005-12-05 09:23 黑马      

 回复 引用 查看   
#8楼[楼主] 2005-12-05 09:42 Terrylee      
@黑马

多谢:)

 回复 引用 查看   
#9楼 2006-09-02 22:27 藤条焖猪肉      
对配置文件加密后,有一个问题,加密配置时产生的<keyAlgorithmStorageProvider 的 entropy是保存在App.config文件,是明文的(一般是不能把App.config加密的吧,否则要用到其他如iBatis等框架的话就会出问题也),而且产生Key的文件也是放在程序下的.,这样的话,(假设对方知道程序所用的加密算法)别人就很容易拿到entropy和Key文件也可以把加密的配置文件解密了,这样的话也是很不安全的。

不知道是不是我的理解错了呢,请指教

 回复 引用   
#11楼 2007-11-12 15:38 XML[未注册用户]
有没有最新的资料?
 回复 引用 查看   
#12楼 2008-06-27 13:21 landylee      
請問配置應用程序塊剖析篇在設計模式的哪一篇可以看到?
 回复 引用 查看   
#13楼 2009-02-05 13:24 colys      
ConfigurationManager.ConfigurationChanged 是fx1.1的吗,fx3.5+entlib4用什么来监视,ConfigurationChangeFileWatcher or FileSystemWatcher,ConfigurationChangeFileWatcher的构造public ConfigurationChangeFileWatcher(string configFilePath, string configurationSectionName),是只能监视一个section吗?