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") == );
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 = ; i < base.Count; i++)
{
yield return base.BaseGet(i) as IItem;
}
}
}

2.自定义NodeElement(INode)和NodeElementCollection用于实现节点树功能。

    public class NodeElement : ConfigurationElement, INode
{
[ConfigurationProperty("name", IsRequired = true)]
public string Name
{
get { return Convert.ToString(this["name"]); }
set { this["name"] = value; }
} [ConfigurationProperty("items")]
[ConfigurationCollection(typeof(ItemElementCollection), AddItemName = "item")]
public ItemElementCollection ItemElements
{
get
{
return this["items"] as ItemElementCollection;
}
set { this["items"] = value; }
} [ConfigurationProperty("nodes")]
[ConfigurationCollection(typeof(NodeElementCollection), AddItemName = "node")]
public NodeElementCollection NodeElements
{
get
{
return this["nodes"] as NodeElementCollection;
}
set { this["nodes"] = value; }
} public IEnumerable<IItem> Items
{
get
{
return this["items"] as ItemElementCollection;
}
set { this["items"] = value; }
} public IEnumerable<INode> Nodes
{
get
{
return this["nodes"] as NodeElementCollection;
}
set { this["nodes"] = value; }
} public string GetItem(string itemName)
{
return this.Items.FirstOrDefault(o => o.Name == itemName)?.Value;
} public T GetItem<T>(string itemName)
{
return (T)Convert.ChangeType(this.GetItem(itemName), typeof(T));
}
}
public class NodeElementCollection : ConfigurationElementCollection, IEnumerable<INode>
{
protected override ConfigurationElement CreateNewElement()
{
return new NodeElement();
} protected override object GetElementKey(ConfigurationElement element)
{
return ((NodeElement)element).Name;
} public new IEnumerator<INode> GetEnumerator()
{
for (int i = ; i < base.Count; i++)
{
yield return base.BaseGet(i) as INode;
}
}
}

3.自定义ConfigSection实现配置节点和配置项读取。

    public class ConfigSection : ConfigurationSection, INode
{
[ConfigurationProperty("name", IsRequired = true)]
public string Name
{
get { return Convert.ToString(this["name"]); }
set { this["name"] = value; }
} [ConfigurationProperty("items")]
[ConfigurationCollection(typeof(ItemElementCollection), AddItemName = "item")]
public ItemElementCollection ItemElements
{
get
{
return this["items"] as ItemElementCollection;
}
set { this["items"] = value; }
} [ConfigurationProperty("nodes")]
[ConfigurationCollection(typeof(NodeElementCollection), AddItemName = "node")]
public NodeElementCollection NodeElements
{
get
{
return (NodeElementCollection)this["nodes"];
}
set { this["nodes"] = value; }
} public IEnumerable<IItem> Items
{
get
{
return this["items"] as ItemElementCollection;
}
set { this["items"] = value; }
} public IEnumerable<INode> Nodes
{
get
{
return (NodeElementCollection)this["nodes"];
}
set { this["nodes"] = value; }
} public string GetItem(string itemName)
{
return this.Items.FirstOrDefault(o => o.Name == itemName)?.Value;
} public T GetItem<T>(string itemName)
{
return (T)Convert.ChangeType(this.GetItem(itemName), typeof(T));
}
}

4.自定义AppConfigAdapter实现IConfig接口。

    public class AppConfigAdapter : IConfig
{
private INode _section; public AppConfigAdapter()
{
var sectionName = (HostingEnvironment.IsHosted ? WebConfigurationManager.OpenWebConfiguration("~") : ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None))
.Sections.Cast<ConfigurationSection>()
.FirstOrDefault(o => o.SectionInformation.Type.IndexOf("Onion.Configuration.AppConfig.ConfigSection") != -)
.SectionInformation.Name ?? "Node";
_section = (INode)ConfigurationManager.GetSection(sectionName);
} public INode GetNode(string nodeName)
{
return this.GetNode(nodeName, this._section);
} public string Get(string nameOrPath)
{
if (nameOrPath.IndexOf('.') == -)
{
return this._section.Items.FirstOrDefault(o => o.Name == nameOrPath)?.Value;
}
var nodeItemPath = nameOrPath.Split('.');
var node = this.GetNode(nodeItemPath.FirstOrDefault());
var nodeNameList = nodeItemPath.Skip().Take(nodeItemPath.Length - );
if (node != null)
{
foreach (var item in nodeNameList)
{
if (node.Nodes.Any(o => o.Name == item))
{
node = node.Nodes.FirstOrDefault(o => o.Name == item);
}
else
{
throw new System.ArgumentException(string.Format("node name {0} error", item));
}
}
return node.Items.FirstOrDefault(o => o.Name == nodeItemPath.LastOrDefault()).Value;
}
return null;
} public T Get<T>(string nameOrPath)
{
var value = this.Get(nameOrPath);
return (T)Convert.ChangeType(value, typeof(T));
} #region private private INode GetNode(string nodeName, INode node)
{
INode result = null; if (node.Name == nodeName)
{
return node;
}
else if (node.Nodes.Any())
{
foreach (var item in node.Nodes)
{
result = GetNode(nodeName, item);
if (result != null)
{
break;
}
}
}
return result;
} #endregion private
}

Nuget:https://www.nuget.org/packages/Onion.Configuration/

ASP.NET系列:自定义配置节点的复用的更多相关文章

  1. App.config和Web.config配置文件的自定义配置节点

    前言 昨天修改代码发现了一个问题,由于自己要在WCF服务接口中添加了一个方法,那么在相应调用的地方进行更新服务就可以了,不料意外发生了,竟然无法更新.左查右查终于发现了问题.App.config配置文 ...

  2. VS2012 常用web.config配置解析之自定义配置节点

    在web.config文件中拥有一个用户自定义配置节点configSections,这个节点可以方便用户在web.config中随意的添加配置节点,让程序更加灵活(主要用于第三方插件的配置使用) 自定 ...

  3. 自定义配置节点configSections的使用

    //App.config <?xml version="1.0" encoding="utf-8" ?><configuration>  ...

  4. C#创建自定义配置节点

    转载:http://www.educity.cn/develop/495003.html 在.Net应用程序中我们经常看到VS为我们生成的项目工程中都会含有app.config或者web.connfi ...

  5. .Net 配置文件--继承ConfigurationSection实现自定义处理类处理自定义配置节点

    除了使用继承IConfigurationSectionHandler的方法定义处理自定义节点的类,还可以通过继承ConfigurationSection类实现同样效果. 首先说下.Net配置文件中一个 ...

  6. .Net 配置文件——继承ConfigurationSection实现自定义处理类处理自定义配置节点

    除了使用继承IConfigurationSectionHandler的方法定义处理自定义节点的类,还可以通过继承ConfigurationSection类实现同样效果. 首先说下.Net配置文件中一个 ...

  7. App.Config自定义配置节点

    配置文件: <?xml version="1.0" encoding="utf-8"?> <configuration> <con ...

  8. .NET中如何自定义配置节点

    .NET Framework在web.config或app.config中默认提供了很多种设置,以便能够改变应用程序内嵌组件的行为,例如<connectionStrings>.<ht ...

  9. C# 快捷使用自定义配置节点

    C#除了appSettings和connectionStrings默认配置外还允许用户自定义使用配置.C# 提供3中简单的自定义配置,配置文件如下 <?xml version="1.0 ...

随机推荐

  1. JSTL-c:forEach标签详解

    c:forEach基本格式: <c:forEach var="每个变量名字" items="要迭代的list" varStatus="每个对象的 ...

  2. GridView的HyperLinkField的DataNavigateUrlFormatString如何使用自定义的变量,而不是数据库绑定的值

    GridView的HyperLinkField的DataNavigateUrlFormatString如何使用自定义的变量,而不是数据库绑定的值.报错:指定的参数已超出有效值的范围.参数名: inde ...

  3. jquery.raty.js 评星插件的使用

    需要实现一个五星好评的功能,所以找到了这个JQ插件,使用起来还算简单,在这里记录下使用的方式. 第一步:导入这个插件和压缩包中的img文件夹 <script type="text/ja ...

  4. ElasticSearch 基础概念学习(未完)

    1.基本定义 摘自百度百科 elasticseaElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口.Elastic ...

  5. 关于Selenium HTMLTestRunner 无法生成测试报告

    解决方法 1: filename = ‘E:\testresult.html’,如果是在windows环境,文件名要使用以下几种格式. ①filename = 'E:\\testresult.html ...

  6. MPI 集合通信函数 MPI_Scatterv(),MPI_Gatherv(),MPI_Allgatherv(),MPI_Alltoall(),MPI_Alltoallv(),MPI_Alltoallw()

    ▶ 函数 MPI_Scatterv() 和 MPI_Gatherv() .注意到函数 MPI_Scatter() 和 MPI_Gather() 只能向每个进程发送或接受相同个数的元素,如果希望各进程获 ...

  7. leetcode205

    public class Solution { public bool IsIsomorphic(string s, string t) { if (s.Length != t.Length) { r ...

  8. .net 架构

    .net Webservice 三层架构,BLL(业务逻辑层),DAL(数据访问层)sql语句.MODEL模型层也就是实体层Entity(数据库字段和类的定义的映射). UI层(Web/Form)界面 ...

  9. 关于hibernate4.3版本之后org.hibernate.service.ServiceRegistryBuilder被弃用

    之前一直都是使用hibernate4.2.21的我,有一天突然没有使用本地的jar包而是让IDEA自动下载最新版本的hibernate5.2.2之后,发现有几个经常使用的方法报错了. -这真是让我惊了 ...

  10. 让 IE6支持max-height

    min-height min-height:100px; _height:100px max-height max-height:200px; overflow:auto;/*超出部分显示滚动条*/ ...