1 配置应用程序块
1.1对元配置文件的操作
在微软企业库(Microsoft Enterprise Library 简称MEL)中,将配置文件分为两类:元配置文件和其他配置文件,其中元配置文件只有一个(一般是系统的配置文件),提供了对其他配置文件进行操作的信息。其它配置文件保存了诸如数据库访问信息、日志记录、异常处理方式、加密、缓存等的配置信息,这些信息可以保存在一个文件中,也可以分别单独保存。
在MEL1.0中,习惯于将对配置的操作和配置的内容分开,对元配置文件的操作也不例外。
对元配置文件的操作由类ConfigurationFile来完成。
AppendSection()
|
在元配置文件添加一个配置节
|
GetConfig()
|
获取元配置文件的内容
|
|
|
元配置文件的数据由类ConfigurationSettings来保存。它包含了一个集合ConfigurationSectionDataCollection,该集合中的每一个元素ConfigurationSectionData有四个属性。
Name
|
配置节名称
|
StorageProvider
|
提供对该配置节对应配置文件的存取
|
Transformer
|
提供对该配置节对应配置文件内容的转换
|
Encrypt
|
配置节的内容是否加密
|
|
|
从上面这个表格可以看出:每一个配置文件对应一个StorageProvider和Transformer,对其他配置文件的操作的关键是StorageProvider和Transformer。
1.2 对其它配置文件的操作
在配置应用程序块中,有一个类非常重要,它就是ConfigurationBuilder,它起到了一个承上启下的作用,对其它配置文件的操作就是由ConfigurationBuilder来完成的。
ReadConfiguration()
|
获取一个配置节的内容
|
WriteConfiguration()
|
将一个配置节的内容保存到相应的配置文件中
|
|
|
其它配置文件的内容缓存在ConfigurationSections中,这个类实际上相当于一个缓存区。
Cache
|
这是一个HashTable,缓存已经获取的配置节内容
|
|
|
1.3 StorageProvider
1.4 Transformer
1.5个人对应用程序块的理解
1.5.1 个人观点
我个人认为在MEL2005设计之初,考虑了多种配置的保存形式,因此导致出现了StorageProvider和Transformer,而配置应用程序块的复杂之处也在于此。而我个人认为不必要考虑配置的多种保存形式,而将配置的保存形式固定为xml文件。这应该能够满足绝大多数系统的应用,并且具有通用性。这样处理之后,配置文件只考虑xml一种形式,这样就不需要StorageProvider和Transformer了,这也是我为什么没有对StorageProvider和Transformer进行深入的分析的缘故。
我个人认为配置管理就是将配置对象序列化到配置文件中以及反序列化的过程,也就是说配置管理是针对配置对象的,而不管这个配置对象代表什么样的配置信息。
我个人认为正是基于上述两点,微软在.net framework2.0 中增加了配置程序集,而MEL2006中也将配置应用程序块去掉了。
1.5.2 个人实践
基于上述观点,我个人设计了自己的配置管理程序集。
1.5.2.1配置文件结构

元配置文件格式如下:
<configuration>
<configSections>
<section name="configurationSettings" type="metaConfig" />
</configSections>
<configurationSettings>
<configurationSection name=”SectionName1" type=”CustomObjects” file="CustomObjects.xml" />
<configurationSection name=”SectionName2" type=”DataAccess” file="DataAcces.xml" />
<configurationSection name=”SectionName3" type=”Log” file=”Log.xml" />
<configurationSection name=”SectionName4" type=”Exception” file="Exception.xml" />
</configurationSettings>
</configuration>
1.5.2.2 类图

1.5.2.3 类ConfigurationManager
该类作为一个用户和配置管理程序集的接口。源代码如下:
public sealed class ConfigurationManager
{
public ConfigurationManager()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
private static MetaConfigFile metaConfigFile=new MetaConfigFile();
public static object GetConfig(string sectionName)
{
Section section = metaConfigFile.GetSection(sectionName);
if(section==null)
{
return null;
}
else
{
return section.GetConfigObject();
}
}
public static void SetConfig(string sectionName,object configValue)
{
Section section = metaConfigFile.GetSection(sectionName);
if(section==null)
{
Section newSection = new Section();
newSection.Name = sectionName;
newSection.Path = sectionName+".xml";
newSection.SaveConfigObject(configValue);
metaConfigFile.AddSection(newSection);
}
else
{
section.SaveConfigObject(configValue);
}
}
}
1.5.2.4 类MetaConfigFile
源代码如下:
public class MetaConfigFile
{
public MetaConfigFile()
{
//
// TODO: 在此处添加构造函数逻辑
//
if (File.Exists(this.configurationFile))
{
XmlDocument doc = new XmlDocument();
doc.Load(configurationFile);
XmlNode configSectionsNode = doc.DocumentElement.SelectSingleNode(configSectionsXPath);
foreach(XmlNode xn in configSectionsNode.ChildNodes)
{
Section section = new Section();
section.Name = xn.Attributes["name"].Value;
section.Path = xn.Attributes["file"].Value;
this.sections.Add(section);
}
}
}
private string configurationFile = "MetaConfiguration.xml";
private ArrayList sections = new ArrayList();
private const string TempFileName = "ApplicationConfig1";
private const string metaRootElement = "myconfiguration";
private const string metaConfigSectionsElement ="configSections";
private const string metaconfigSectionElement = "section";
private const string metaConfigSectionElementName ="configurationSettings";
private const string metaConfigSectionElementType="metaConfig";
private const string configSectionsXPath = "//myconfiguration/configurationSettings";
private const string configSectionElment="configurationSection";
public Section GetSection(string sectionName)
{
Section section=null;
for(int index=0;index<this.sections.Count;index++)
{
section=(Section)sections[index];
if(section.Name==sectionName)
{
return section;
}
}
return null;
}
public void AddSection(Section section)
{
sections.Add(section);
XmlDocument doc = new XmlDocument();
doc.Load(this.configurationFile);
XmlNode configSectionsNode = doc.DocumentElement.SelectSingleNode(configSectionsXPath);
XmlElement xe=doc.CreateElement(configSectionElment);//创建一个节点
xe.SetAttribute("name",section.Name);//设置该节点name属性
xe.SetAttribute("file",section.Path);//设置该节点file属性
configSectionsNode.AppendChild(xe);
doc.Save(this.configurationFile);
}
}
1.5.2.5 类Section
源代码如下:
public class Section
{
public Section()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
public string Name;
public string Path;
public object GetConfigObject()
{
XmlDocument xmlConfigFile = new XmlDocument();
xmlConfigFile.Load(this.Path);
XmlNode sectionNode = xmlConfigFile.DocumentElement;
XmlAttribute typeAttribute = sectionNode.Attributes["type"];
string typeName = typeAttribute.Value;
Type classType = Type.GetType(typeName, true);
XmlSerializer xs = new XmlSerializer(classType);
return xs.Deserialize(new XmlNodeReader(sectionNode.ChildNodes[0]));
}
public void SaveConfigObject(object tconfigValue)
{
Type type = tconfigValue.GetType();
XmlSerializer xmlSerializer = new XmlSerializer(type);
StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter);
XmlDocument doc = new XmlDocument();
try
{
xmlTextWriter.WriteStartElement("xmlSerializerSection");
xmlTextWriter.WriteAttributeString("type",tconfigValue.GetType().AssemblyQualifiedName);
xmlSerializer.Serialize(xmlTextWriter, tconfigValue);
xmlTextWriter.WriteEndElement();
xmlTextWriter.Flush();
doc.LoadXml(stringWriter.ToString());
doc.Save(this.Path);
}
finally
{
xmlTextWriter.Close();
stringWriter.Close();
}
}
}
1.5.3 小结
用上述三个类即可实现一般的配置存取功能。注意:
1. 在类MetaConfigFile中用configurationFile 保存元配置文件名为MetaConfiguration.xml,可根据实际情况修改;
2. 在上述源代码中没有进行异常处理,可自行添加;
3. 在上述源代码中没有添加配置变动事件处理,可自行参照EML2005添加;
4. 在上述源代码中没有进行并发处理,可自行添加;
5. 在上述源代码中测试性能,可自行优化;