原帖地址:应用程序配置文件问题
配置文件如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="RinexHeader" type="System.Configuration.NameValueSectionHandler"/>
</configSections>
<RinexHeader>
<!--O文件文件头标签字符串集合,和OHeaderLabel中的枚举值要一一对应-->
<add key="OHeadLabel" value="RINEX VERSION / TYPE"/>
<add key="OHeadLabel" value="PGM / RUN BY / DATE"/>
<add key="OHeadLabel" value="COMMENT"/>
</RinexHeader>
</configuration>
文中网友使用 NameValueSectionHandler 来处理 configuration section,他的问题是为什么 OHeadLabel 只取到一个,而不是多个。
这里要说明一下, NameValueSectionHandler 在处理 configuration section 的时候,使用的方式是
ReadOnlyNameValueCollectionInstance[key] = value;
这样相同 key 只会保留最后一个,之前的都会被覆盖掉。
所以在这里 NameValueSectionHandler 是不能胜任的。
还要说明下 NameValueSectionHandler 和 DictionarySectionHandler 除了在 GetSection 时返回类型不同外,基本相同。
因为 DictionarySectionHandler 返回的是哈希表,所以在大量节点的情况下后续查找的速度会比 NameValueSectionHandler 快。
为了实现需求,我们可以自定义 configuration section handler
思路很简单,在原本返回单个节点的属性值的地方返回集合。
具体代码如下:
public class CustomSectionHandler : IConfigurationSectionHandler
{
#region IConfigurationSectionHandler Members
object IConfigurationSectionHandler.Create(
object parent, object configContext, XmlNode section)
{
// Creates the configuration object that this method will return.
// This can be a custom configuration class.
// In this example, we use a System.Collections.Generic.IDictionary<string, IList<string>>.
IDictionary<string, IList<IDictionary<string, string>>> myConfigObject = new Dictionary<string, IList<IDictionary<string, string>>>();
// Gets any attributes for this section element.
IDictionary<string, string> myAttribs = new Dictionary<string, string>();
foreach (XmlAttribute attrib in section.Attributes)
{
if (XmlNodeType.Attribute == attrib.NodeType)
myAttribs.Add(attrib.Name, attrib.Value);
}
IList<IDictionary<string, string>> list = new List<IDictionary<string, string>>();
// Puts the section name and attributes as the first config object item.
list.Add(myAttribs);
myConfigObject.Add(section.Name, list);
// Gets the child element names and attributes.
foreach (XmlNode child in section.ChildNodes)
{
if (XmlNodeType.Element == child.NodeType)
{
IDictionary<string, string> myChildAttribs = new Dictionary<string, string>();
foreach (XmlAttribute childAttrib in child.Attributes)
{
if (XmlNodeType.Attribute == childAttrib.NodeType)
myChildAttribs.Add(childAttrib.Name, childAttrib.Value);
}
if (myConfigObject.ContainsKey(myChildAttribs["key"]))
{
myConfigObject[myChildAttribs["key"]].Add(myChildAttribs);
}
else
{
list = new List<IDictionary<string, string>>();
list.Add(myChildAttribs);
myConfigObject.Add(myChildAttribs["key"], list);
}
}
}
return (myConfigObject);
}
#endregion
}
设置config
<configSections>
<section name="RinexHeader" type="namespace.CustomSectionHandler,namespace, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</configSections>
调用代码
IDictionary<string, IList<IDictionary<string, string>>> dic = System.Configuration.ConfigurationManager.GetSection("RinexHeader") as Dictionary<string, IList<IDictionary<string, string>>>;
if (dic.ContainsKey("OHeadLabel"))
{
foreach (var v in dic["OHeadLabel"])
{
Console.WriteLine(v["value"]);
}
}
虽然实现了功能,但也暴露了问题 if (myConfigObject.ContainsKey(myChildAttribs["key"])) 可以看到 key 是硬编码在这的,这并不是一个好的实现。
而且配置文件中
<add key="OHeadLabel" value="RINEX VERSION / TYPE"/>
<add key="OHeadLabel" value="PGM / RUN BY / DATE"/>
<add key="OHeadLabel" value="COMMENT"/>
add 毫无意义,所以应改成
<OHeadLabel value="RINEX VERSION / TYPE"/>
<OHeadLabel value="PGM / RUN BY / DATE"/>
<OHeadLabel value="COMMENT"/>
然后修改之前的程序,myChildAttribs["key"] => child.Name
修改后的代码:
public class CustomSectionHandler : IConfigurationSectionHandler
{
#region IConfigurationSectionHandler Members
object IConfigurationSectionHandler.Create(
object parent, object configContext, XmlNode section)
{
// Creates the configuration object that this method will return.
// This can be a custom configuration class.
// In this example, we use a System.Collections.Generic.IDictionary<string, IList<string>>.
IDictionary<string, IList<IDictionary<string, string>>> myConfigObject = new Dictionary<string, IList<IDictionary<string, string>>>();
// Gets any attributes for this section element.
IDictionary<string, string> myAttribs = new Dictionary<string, string>();
foreach (XmlAttribute attrib in section.Attributes)
{
if (XmlNodeType.Attribute == attrib.NodeType)
myAttribs.Add(attrib.Name, attrib.Value);
}
IList<IDictionary<string, string>> list = new List<IDictionary<string, string>>();
// Puts the section name and attributes as the first config object item.
list.Add(myAttribs);
myConfigObject.Add(section.Name, list);
// Gets the child element names and attributes.
foreach (XmlNode child in section.ChildNodes)
{
if (XmlNodeType.Element == child.NodeType)
{
IDictionary<string, string> myChildAttribs = new Dictionary<string, string>();
foreach (XmlAttribute childAttrib in child.Attributes)
{
if (XmlNodeType.Attribute == childAttrib.NodeType)
myChildAttribs.Add(childAttrib.Name, childAttrib.Value);
}
if (myConfigObject.ContainsKey(child.Name))
{
myConfigObject[child.Name].Add(myChildAttribs);
}
else
{
list = new List<IDictionary<string, string>>();
list.Add(myChildAttribs);
myConfigObject.Add(child.Name, list);
}
}
}
return (myConfigObject);
}
#endregion
}
大功告成。