ASP.NET系列:自定义配置节点的复用
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;}}} View Code?
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 = 0; i < base.Count; i++){yield return base.BaseGet(i) as INode;}}} View Code?
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));}} View Code?
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") != -1).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('.') == -1){return this._section.Items.FirstOrDefault(o => o.Name == nameOrPath)?.Value;}var nodeItemPath = nameOrPath.Split('.');var node = this.GetNode(nodeItemPath.FirstOrDefault());var nodeNameList = nodeItemPath.Skip(1).Take(nodeItemPath.Length - 2);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 privateprivate 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} View Code?
Nuget:https://www.nuget.org/packages/Onion.Configuration/
轉載于:https://www.cnblogs.com/easygame/p/5051592.html
總結
以上是生活随笔為你收集整理的ASP.NET系列:自定义配置节点的复用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 巧用JSON.stringify()生成
- 下一篇: CentOS中安装Docker步骤