zoukankan      html  css  js  c++  java
  • 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 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
        }
    View Code

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

  • 相关阅读:
    CF1029C Maximal Intersection 暴力枚举
    2018中国大学生程序设计竞赛
    php远程抓取(下载)文件到本项目指定目录中
    FCKEditor添加字体
    UCenter 与 DIscuz 通信失败的解决方法
    运用php函数mkdir创建多级目录
    PHP 数组函数-数组排序
    php登陆ssh执行命令
    php定时执行任务的几个方法
    PHP Yii框架中使用smarty模板
  • 原文地址:https://www.cnblogs.com/easygame/p/5051592.html
Copyright © 2011-2022 走看看