ASP.NET系列:自定义配置节点的复用

王朝学院·作者佚名  2016-08-28
窄屏简体版  字體: 小  |  中  |  大  |  超大  

appSettings太简单,为每个程序自定义配置节点太复杂,因此要解决app.config&web.config自定义配置的复用问题。

1.读取不依赖SectionName,根节点可以定义为任何名称。

2.足够简单,配置项采用name value的形式;足够复杂,采用树型结构,每个节点都可以有多个配置项和子节点。

3.使用简单,采用路径简化配置项的读取。如: config.Get<string>("root.sub.item-test")。

一、调用方式:1.配置文件:

<?xmlversion="1.0" encoding="utf-8"?><configuration><configSections><sectionname="node"type="Onion.Configuration.AppConfig.ConfigSection,Onion.Configuration"/></configSections><nodename="root"><items><itemname="version"value="1.0.0.1"/></items><nodes><nodename="runtime"><items><itemname="debug"value="false"/><itemname="ioc"value="IoC.Contianer.StructureMapIoC"/></items></node><nodename="upload"><items><itemname="auth"value="true"/><itemname="path"value="~/upload"/><itemname="url"value="~/Upload/Index"/></items></node><nodename="captcha"><items><itemname="timeout"value="3000"/><itemname="url"value="~/Captcha/Index"/></items></node><nodename="oauth2"><items><itemname="disabled"value="false"/><itemname="callback"value="/Home/ExternalLoginCallBack?PRoviderName="/></items><nodes><nodename="QQclient"><items><itemname="disabled"value="false"/><itemname="method"value="get"/><itemname="key"value="9233e24d"/><itemname="secret"value="1ac35907-7cfa-4079-975c-959b98d23a95"/></items></node><nodename="weiboclient"><items><itemname="disabled"value="true"/><itemname="method"value="post"/><itemname="key"value="0cdea8f3"/><itemname="secret"value="dc679dbb-7e75-44f7-a99e-5359259fc94b"/></items></node></nodes></node></nodes></node></configuration>

2.调用代码:

[Fact]publicvoidTests()

{varconfig =newAppConfigAdapter();

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(varnodeinconfig.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");

}elseif(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用于实现单个节点的配置项读取。

[flash=500,400]http://s1.knowsky.com/20160211/dxkkierjalu21.gif[/flash][flash=500,400]http://s1.knowsky.com/20160211/gw42gquvzty21.gif[/flash]publicclassItemElement : ConfigurationElement, IItem

{

[ConfigurationProperty("name", IsRequired =true)]publicstringName

{get{returnConvert.ToString(this["name"]); }set{this["name"] =value; }

}

[ConfigurationProperty("value", IsRequired =true)]publicstringValue

{get{returnConvert.ToString(this["value"]); }set{this["value"] =value; }

}

}publicclassItemElementCollection : ConfigurationElementCollection, IEnumerable<IItem>{protectedoverrideConfigurationElement CreateNewElement()

{returnnewItemElement();

}protectedoverrideobjectGetElementKey(ConfigurationElement element)

{return((ItemElement)element).Name;

}publicnewIEnumerator<IItem>GetEnumerator()

{for(inti =0; i <base.Count; i++)

{yieldreturnbase.BaseGet(i)asIItem;

}

}

}

View Code

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

[flash=500,400]http://s1.knowsky.com/20160211/dxkkierjalu21.gif[/flash][flash=500,400]http://s1.knowsky.com/20160211/gw42gquvzty21.gif[/flash]publicclassNodeElement : ConfigurationElement, INode

{

[ConfigurationProperty("name", IsRequired =true)]publicstringName

{get{returnConvert.ToString(this["name"]); }set{this["name"] =value; }

}

[ConfigurationProperty("items")]

[ConfigurationCollection(typeof(ItemElementCollection), AddItemName ="item")]publicItemElementCollection ItemElements

{get{returnthis["items"]asItemElementCollection;

}set{this["items"] =value; }

}

[ConfigurationProperty("nodes")]

[ConfigurationCollection(typeof(NodeElementCollection), AddItemName ="node")]publicNodeElementCollection NodeElements

{get{returnthis["nodes"]asNodeElementCollection;

}set{this["nodes"] =value; }

}publicIEnumerable<IItem>Items

{get{returnthis["items"]asItemElementCollection;

}set{this["items"] =value; }

}publicIEnumerable<INode>Nodes

{get{returnthis["nodes"]asNodeElementCollection;

}set{this["nodes"] =value; }

}publicstringGetItem(stringitemName)

{returnthis.Items.FirstOrDefault(o => o.Name == itemName)?.Value;

}publicT GetItem<T>(stringitemName)

{return(T)Convert.ChangeType(this.GetItem(itemName),typeof(T));

}

}publicclassNodeElementCollection : ConfigurationElementCollection, IEnumerable<INode>{protectedoverrideConfigurationElement CreateNewElement()

{returnnewNodeElement();

}protectedoverrideobjectGetElementKey(ConfigurationElement element)

{return((NodeElement)element).Name;

}publicnewIEnumerator<INode>GetEnumerator()

{for(inti =0; i <base.Count; i++)

{yieldreturnbase.BaseGet(i)asINode;

}

}

}

View Code

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

[flash=500,400]http://s1.knowsky.com/20160211/dxkkierjalu21.gif[/flash][flash=500,400]http://s1.knowsky.com/20160211/gw42gquvzty21.gif[/flash]publicclassConfigSection : ConfigurationSection, INode

{

[ConfigurationProperty("name", IsRequired =true)]publicstringName

{get{returnConvert.ToString(this["name"]); }set{this["name"] =value; }

}

[ConfigurationProperty("items")]

[ConfigurationCollection(typeof(ItemElementCollection), AddItemName ="item")]publicItemElementCollection ItemElements

{get{returnthis["items"]asItemElementCollection;

}set{this["items"] =value; }

}

[ConfigurationProperty("nodes")]

[ConfigurationCollection(typeof(NodeElementCollection), AddItemName ="node")]publicNodeElementCollection NodeElements

{get{return(NodeElementCollection)this["nodes"];

}set{this["nodes"] =value; }

}publicIEnumerable<IItem>Items

{get{returnthis["items"]asItemElementCollection;

}set{this["items"] =value; }

}publicIEnumerable<INode>Nodes

{get{return(NodeElementCollection)this["nodes"];

}set{this["nodes"] =value; }

}publicstringGetItem(stringitemName)

{returnthis.Items.FirstOrDefault(o => o.Name == itemName)?.Value;

}publicT GetItem<T>(stringitemName)

{return(T)Convert.ChangeType(this.GetItem(itemName),typeof(T));

}

}

View Code

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

[flash=500,400]http://s1.knowsky.com/20160211/dxkkierjalu21.gif[/flash][flash=500,400]http://s1.knowsky.com/20160211/gw42gquvzty21.gif[/flash]publicclassAppConfigAdapter : IConfig

{privateINode _section;publicAppConfigAdapter()

{varsectionName = (HostingEnvironment.IsHosted ? WebConfigurationManager.OpenWebConfiguration("~") : ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None))

.Sections.Cast<ConfigurationSection>()

.FirstOrDefault(o=> o.SectionInformation.Type.IndexOf("Onion.Configuration.AppConfig.ConfigSection") != -1)

.SectionInformation.Name??"Node";

_section=(INode)ConfigurationManager.GetSection(sectionName);

}publicINode GetNode(stringnodeName)

{returnthis.GetNode(nodeName,this._section);

}publicstringGet(stringnameOrPath)

{if(nameOrPath.IndexOf('.') == -1)

{returnthis._section.Items.FirstOrDefault(o => o.Name == nameOrPath)?.Value;

}varnodeItemPath = nameOrPath.Split('.');varnode =this.GetNode(nodeItemPath.FirstOrDefault());varnodeNameList = nodeItemPath.Skip(1).Take(nodeItemPath.Length -2);if(node !=null)

{foreach(variteminnodeNameList)

{if(node.Nodes.Any(o => o.Name ==item))

{

node= node.Nodes.FirstOrDefault(o => o.Name ==item);

}else{thrownewSystem.ArgumentException(string.Format("node name {0} error", item));

}

}returnnode.Items.FirstOrDefault(o => o.Name ==nodeItemPath.LastOrDefault()).Value;

}returnnull;

}publicT Get<T>(stringnameOrPath)

{varvalue =this.Get(nameOrPath);return(T)Convert.ChangeType(value,typeof(T));

}#regionprivateprivateINode GetNode(stringnodeName, INode node)

{

INode result=null;if(node.Name ==nodeName)

{returnnode;

}elseif(node.Nodes.Any())

{foreach(variteminnode.Nodes)

{

result=GetNode(nodeName, item);if(result !=null)

{

break;

}

}

}returnresult;

}#endregionprivate}

View Code

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

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航