Detail solution for adding custom configuration in Web.config or App.config

  • 2020-06-07 04:22:04
  • OfStack

The System.Configuration namespace in.Net provides perfect support for our custom configurations in web.config or app.config. Recently, I saw some projects that were still using custom xml files for program configuration, so I couldn't resist writing a post about using system custom configuration.
If you are already familiar with custom configurations, please ignore this article. The & # 61514;
Without further discussion, let's look at one of the simplest custom configurations

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
  <configSections> 
    <section name="simple" type="ConfigExample.Configuration.SimpleSection,ConfigExample"/> 
  </configSections> 
  <simple maxValue="20" minValue="1"></simple> 
</configuration> 

To use a custom configuration in a configuration file, you need to add an section element to configSections and specify the type and name for this section element. Then add this custom configuration below the configuration root node, as in the example above. The simple node has only two properties. maxValue and minValue.
To use a custom configuration in your program, you also need to implement the type that accesses this configuration block.
1. Definition types inherit from System.Configuration.ConfigurationSection
2. Define the properties of the configuration class that need to be decorated with the ConfigurationProperty property, and specify the name of the property in the configuration section and some other restriction information
3. Implement the attribute get, set through the base class's string indexer
Very simple and natural, here is the implementation of the configuration class above:

public class SimpleSection:System.Configuration.ConfigurationSection 
{ 
    [ConfigurationProperty("maxValue",IsRequired=false,DefaultValue=Int32.MaxValue)] 
    public int MaxValue 
    { 
        get
        { 
            return  (int)base["maxValue"]; 
        } 
        set
        { 
            base["maxValue"] = value; 
        } 
    } 

    [ConfigurationProperty("minValue",IsRequired=false,DefaultValue=1)] 
    public int MinValue 
    { 
        get { return (int) base["minValue"];} 
        set { base["minValue"] = value; } 
    } 

  
    [ConfigurationProperty("enabled",IsRequired=false,DefaultValue=true)] 
    public bool Enable 
    { 
        get
        { 
            return (bool)base["enabled"]; 
        } 
        set
        { 
            base["enabled"] = value; 
        } 
    } 
}

So a simple configuration class is done. How do you use this configuration in your application? You need to get the configuration using the GetSection method of the ConfigurationManager class (to refer to System.configuration.dll, which is only available in versions after.Net2.0). The following code:

SimpleSection simple = ConfigurationManager.GetSection("simple") as SimpleSection; 
Console.WriteLine("simple minValue={0} maxValue = {1}",simple.MinValue,simple.MaxValue); 

This configuration class is too simple, and sometimes we need more complex constructs, such as using a class to represent a set of data in the configuration class. Let's look at a slightly more complex custom configuration

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
  <configSections> 
    <section name="complex" type="ConfigExample.Configuration.ComplexSection,ConfigExample"/> 
  </configSections> 
  <complex height="190"> 
    <child firstName="James" lastName="Bond"/> 
  </complex> 
</configuration> 

This configuration is called complex, and it has 1 attribute height, and it has an child element inside its node that has 2 attributes firstName and lastName; How do you implement this embedded node? First we need to define a class that inherits from the ConfigurationElement class, and then we need to use methods similar to SimpleSection to define the attributes that are modified by the ConfigurationProperty property. Of course, the attribute values of get and set also use the indexer of the base class. The implementation is as follows:

public class ComplexSection : ConfigurationSection 
{ 
    [ConfigurationProperty("height", IsRequired = true)] 
    public int Height 
    { 
        get
        { 
            return (int)base["height"]; 
        } 
        set
        { 
            base["height"] = value; 
        } 
    } 

    [ConfigurationProperty("child", IsDefaultCollection = false)] 
    public ChildSection Child 
    { 
        get
        { 
            return (ChildSection)base["child"]; 
        } 
        set
        { 
            base["child"] = value; 
        } 
    } 
} 

public class ChildSection : ConfigurationElement 
{ 
    [ConfigurationProperty("firstName", IsRequired = true, IsKey = true)] 
    public string FirstName 
    { 
        get
        { 
            return (string)base["firstName"]; 
        } 
        set
        { 
            base["firstName"] = value; 
        } 
    } 

    [ConfigurationProperty("lastName", IsRequired = true)] 
    public string LastName 
    { 
        get
        { 
            return (string)base["lastName"]; 
        } 
        set
        { 
            base["lastName"] = value; 
        } 
    } 
}

In a slightly more complicated case, we might want to configure a set of nodes of the same type, which is a set of nodes. The following configuration:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
  <configSections> 
    <section name="complex" type="ConfigExample.Configuration.ComplexSection,ConfigExample"/> 
  </configSections> 
  <complex height="190"> 
    <child firstName="James" lastName="Bond"/> 

    <children> 
      <add firstName="Zhao" lastName="yukai"/> 
      <add firstName="Lee" lastName="yukai"/> 
      <remove firstName="Zhao"/> 
    </children> 
  </complex> 
</configuration> 

Look at the children node, which is a collection class that defines a set of add elements, or remove nodes that remove the added configuration.
To use the custom node set, you need to inherit one custom class from the ConfigurationElementCollection class, and then implement the GetElementKey(ConfigurationElement element) and ConfigurationElement CreateNewElement() methods. A read-only indexer can be defined in this class for easy access to child nodes. See the implementation below

public class Children : ConfigurationElementCollection 
{ 
    protected override object GetElementKey(ConfigurationElement element) 
    { 
        return ((ChildSection)element).FirstName; 
    } 

    protected override ConfigurationElement CreateNewElement() 
    { 
        return new ChildSection(); 
    } 

    public ChildSection this[int i] 
    { 
        get
        { 
            return (ChildSection)base.BaseGet(i); 
        } 
    } 

    public ChildSection this[string key] 
    { 
        get
        { 
            return (ChildSection)base.BaseGet(key); 
        } 
    } 

}

Of course, to use this collection class, we must add an attribute of this collection class to the Complex class, and specify the element type and other attributes of the collection class, as follows:

[ConfigurationProperty("children", IsDefaultCollection = false)] 
    [ConfigurationCollection(typeof(ChildSection), CollectionType = ConfigurationElementCollectionType.AddRemoveClearMap, RemoveItemName = "remove")] 
    public Children Children 
    { 
        get
        { 
            return (Children)base["children"]; 
        } 
        set
        { 
            base["children"] = value; 
        } 
}

We often use a key-value pair construct like the appSettings configuration section, and instead of having to implement it ourselves, we can define a custom key-value pair using the existing ES83en.Configuration.NameValueConfigurationCollection class. The following attributes can be defined in the Complex class

[ConfigurationProperty("NVs", IsDefaultCollection = false)] 
    public System.Configuration.NameValueConfigurationCollection NVs 
    { 
        get
        { 
            return (NameValueConfigurationCollection)base["NVs"]; 
        } 
        set
        { 
            base["NVs"] = value; 
        } 
}

Then add the key-value pair configuration in the complex section of the configuration file

<NVs> 
    <add name="abc" value="123"/> 
    <add name="abcd" value="12d3"/> 
</NVs> 

At this point, almost all of the configuration requirements are met. But there is a bigger but less complicated concept, sectionGroup. We can customize SectionGroup and then configure multiple section in sectionGroup. Grouping makes sense for large applications.
In the following configuration, an sectionGroup containing both simple and complex is configured

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
  <configSections> 
    <sectionGroup type="ConfigExample.Configuration.SampleSectionGroup,ConfigExample" name="sampleGroup"> 
      <section type="ConfigExample.Configuration.SimpleSection,ConfigExample" allowDefinition="Everywhere" name="simple" /> 
      <section type="ConfigExample.Configuration.ComplexSection,ConfigExample" allowDefinition="Everywhere" name="complex"/> 
    </sectionGroup> 
  </configSections> 
  <sampleGroup> 
    <simple maxValue="20" minValue="1"> 
    </simple> 

    <complex height="190"> 
      <child firstName="James" lastName="Bond"/> 
      <children> 
        <add firstName="Zhao" lastName="yukai"/> 
        <add firstName="Lee" lastName="yukai"/> 
        <remove firstName="Zhao"/> 
      </children> 
  <NVs> 
    <add name="abc" value="123"/> 
    <add name="abcd" value="12d3"/> 
  </NVs> 
    </complex> 
  </sampleGroup> 
</configuration>

To facilitate access to section in sectionGroup we can implement a custom class inherited from the ES108en.Configuration.ConfigurationSectionGroup class. The implementation is as simple as returning Section through the base class's Sections[" sectionName "] indexer. As follows:

public class SampleSectionGroup : System.Configuration.ConfigurationSectionGroup 
{ 
    public SimpleSection Simple 
    { 
        get
        { 
            return (SimpleSection)base.Sections["simple"]; 
        } 
    } 

    public ComplexSection Complex 
    { 
        get
        { 
            return (ComplexSection)base.Sections["complex"]; 
        } 
    } 
}

It should be noted that SectionGroup cannot be obtained using the ES118en.GetSection (string) method. To obtain sectionGroup, it must be obtained through the SectionGroups[string] indexer of the Configuration class, as shown in the following example code:

SampleSectionGroup sample = (SampleSectionGroup)ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).SectionGroups["sampleGroup"]; 

Conclusion:
.Net framework provides us with a very convenient set of configuration libraries. We only need to inherit the simple configuration 1 of the corresponding class to use the custom nodes configured in web.config or ES133en.config.
Custom configuration file section source code

Related articles: