appSettings太简单,为每个程序自定义配置节点太复杂,因此要解决app.config&web.config自定义配置的复用问题。
1.读取不依赖SectionName,根节点可以定义为任何名称。
2.足够简单,配置项采用name value的形式;足够复杂,采用树型结构,每个节点都可以有多个配置项和子节点。
3.使用简单,采用路径简化配置项的读取。如: config.Get<string>("root.sub.item-test")。
一、调用方式:
1.配置文件:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="node" type="Onion.Configuration.AppConfig.ConfigSection,Onion.Configuration" /> </configSections> <node name="root"> <items> <item name="version" value="1.0.0.1" /> </items> <nodes> <node name="runtime"> <items> <item name="debug" value="false" /> <item name="ioc" value="IoC.Contianer.StructureMapIoC" /> </items> </node> <node name="upload"> <items> <item name="auth" value="true" /> <item name="path" value="~/upload" /> <item name="url" value="~/Upload/Index" /> </items> </node> <node name="captcha"> <items> <item name="timeout" value="3000" /> <item name="url" value="~/Captcha/Index" /> </items> </node> <node name="oauth2"> <items> <item name="disabled" value ="false" /> <item name="callback" value ="/Home/ExternalLoginCallBack?ProviderName=" /> </items> <nodes> <node name="qqclient"> <items> <item name="disabled" value="false" /> <item name="method" value="get" /> <item name="key" value="9233e24d" /> <item name="secret" value="1ac35907-7cfa-4079-975c-959b98d23a95" /> </items> </node> <node name="weiboclient"> <items> <item name="disabled" value="true" /> <item name="method" value="post" /> <item name="key" value="0cdea8f3" /> <item name="secret" value="dc679dbb-7e75-44f7-a99e-5359259fc94b" /> </items> </node> </nodes> </node> </nodes> </node> </configuration>
2.调用代码:
[Fact] public void Tests() { var config = new AppConfigAdapter(); Assert.True(config.Get<string>("version") == "1.0.0.1"); Assert.True(config.Get<bool>("runtime.debug") == false); Assert.True(config.Get<string>("runtime.ioc") == "IoC.Contianer.StructureMapIoC"); Assert.True(config.Get<bool>("upload.auth") == true); Assert.True(config.Get<string>("upload.path") == "~/upload"); Assert.True(config.Get<string>("upload.url") == "~/Upload/Index"); Assert.True(config.Get<int>("captcha.timeout") == 3000); Assert.True(config.Get<string>("captcha.url") == "~/Captcha/Index"); Assert.True(config.Get<bool>("oauth2.disabled") == false); Assert.True(config.Get<string>("oauth2.callback") == "/Home/ExternalLoginCallBack?ProviderName="); Assert.True(config.GetNode("oauth2").Nodes.Any(o => o.GetItem<bool>("disabled"))); foreach (var node in config.GetNode("oauth2").Nodes) { if (node.Name == "qqclient") { Assert.True(node.GetItem<bool>("disabled") == false); Assert.True(node.GetItem<string>("method") == "get"); Assert.True(node.GetItem<string>("key") == "9233e24d"); Assert.True(node.GetItem<string>("secret") == "1ac35907-7cfa-4079-975c-959b98d23a95"); } else if (node.Name == "weiboclient") { Assert.True(node.GetItem<bool>("disabled") == true); Assert.True(node.GetItem<string>("method") == "post"); Assert.True(node.GetItem<string>("key") == "0cdea8f3"); Assert.True(node.GetItem<string>("secret") == "dc679dbb-7e75-44f7-a99e-5359259fc94b"); } } }
二、接口定义:
1.配置项定义:IItem接口定义最基础的配置项,只包含Name和Value属性。
public interface IItem
{
string Name { get; set; }
string Value { get; set; }
}
2.配置节点定义:INode接口定义了配置节点的树形结构
public interface INode
{
string Name { get; set; }
IEnumerable<IItem> Items { get; set; }
IEnumerable<INode> Nodes { get; set; }
string GetItem(string itemName);
T GetItem<T>(string itemName);
}
3.读取接口定义:IConfig接口定义了配置节点和配置项的读取
public interface IConfig
{
INode GetNode(string nodeName);
string Get(string nameOrPath);
T Get<T>(string nameOrPath);
}
以上3个接口定义了所有的逻辑。
三、接口实现:
1.自定义ItemElement(IItem)和ItemElementCollection用于实现单个节点的配置项读取。
public class ItemElement : ConfigurationElement, IItem { [ConfigurationProperty("name", IsRequired = true)] public string Name { get { return Convert.ToString(this["name"]); } set { this["name"] = value; } } [ConfigurationProperty("value", IsRequired = true)] public string Value { get { return Convert.ToString(this["value"]); } set { this["value"] = value; } } } public class ItemElementCollection : ConfigurationElementCollection, IEnumerable<IItem> { protected override ConfigurationElement CreateNewElement() { return new ItemElement(); } protected override object GetElementKey(ConfigurationElement element) { return ((ItemElement)element).Name; } public new IEnumerator<IItem> GetEnumerator() { for (int i = 0; i < base.Count; i++) { yield return base.BaseGet(i) as IItem; } } }