你的位置:首页 > ASP.net教程

[ASP.net教程]ASP.NET系列:自定义配置节点的复用


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

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

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

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

一、调用方式:

1.配置文件:

<??><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