0
votes

Because my new project has a complex configuration structure I'm learning how to use class ConfigurationManager with Custom Configurations.

To do this, I used MSDN How to: Create Custom Configuration Sections Using ConfigurationSection as an example. This example shows a configuration section for a class that aggregates other configurable classes.

MyProblem: ConfigurationManager.GetSection does not return a section

I created a ConsoleApplication.

  • Namespace: TryConfigManagement
  • Add reference: System.Configuration
  • Changed App.Config (copy always) as follows:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
    
      <!-- Configuration section-handler declaration area.  -->
      <configSections>
        <sectionGroup name="pageAppearanceGroup">
          <section
            name="pageAppearance"
            type="TryConfigManagement.PageAppearance"
            allowLocation="true"
            allowDefinition="Everywhere"
            />
        </sectionGroup>
      </configSections>
    
      <!-- Configuration section settings area. -->
      <pageAppearanceGroup>
        <pageAppearance remoteOnly="true">
          <font name="TimeNewRoman" size="18"/>
          <color background="000000" foreground="FFFFFF"/>
        </pageAppearance>  
      </pageAppearanceGroup>
    
      <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
      </startup>
    </configuration>
    

Note that I used a configuration group as in the example from MSDN.

My source code:

namespace TryConfigManagement
{
    class Program
    {
        static void Main(string[] args)
        {
            string sectionName = "pageAppearanceGroup/pageAppearance";
            object section = ConfigurationManager.GetSection(sectionName);

This piece of code throws the following exception:

An error occurred creating the configuration section handler
for pageAppearanceGroup/pageAppearance:
Could not load type 'TryConfigManagement.PageAppearanceSection'
from assembly 'System.Configuration, Version=4.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
(C:\...\bin\Debug\TryConfigManagement.vshost.exe.config line 6)

Although I did exactly what was in the example I figured out from StackOverflow that I should add the assembly information, probably like below:

class Program
{
    static void Main(string[] args)
    {
        var assembly = Assembly.GetExecutingAssembly();
        string sectionName = "pageAppearanceGroup/pageAppearance ," +
            assembly.FullName;
        object section = ConfigurationManager.GetSection(sectionName);

Now the exception is not thrown anymore, but the returned value is null.

I think it has to do with the type in the section name of the config file. However trying different values like adding full assembly name didn't help.

Alas I can't find a lot of information about the string parameter in GetSection.

So what is wrong with my app.config, or with my GetSection call?

2

2 Answers

0
votes

You can try to specify the assembly where TryConfigManagement.PageAppearance type is located in your config:

 <sectionGroup name="pageAppearanceGroup">
      <section
        name="pageAppearance"
        type="TryConfigManagement.PageAppearance, TryConfigManagement"
        allowLocation="true"
        allowDefinition="Everywhere"
        />
    </sectionGroup>

Then don't include the assembly name in GetSection parameter.

Also, remove the space after your section name.

0
votes

Smiech's comment about case sensitivity helped (thanx Smiech!), but it was not the complete answer.

Instead of magic string handling like "pageAppearanceGroup/pageAppearance it is much easier to read and maintain if the classes ConfigurationSectionGroupCollection and ConfigurationSectionCollection are used.

The code would look like follows:

namespace MyNameSpace
{
    class Program
    {
        static void Main(string[] args)
        {
            const string configGroupName = "pageAppearanceGroup";
            const string configSectionName = "pageAppearance";

            Configuration config =  ConfigurationManager.OpenExeConfiguration (ConfigurationUserLevel.None);
            ConfigurationSectionGroup configGroup = config.SectionGroups[configGroupName];
            PageAppearanceSection pageAppearanceConfig = (PageAppearanceSection)configGroup.Sections[configSectionName];

After these I could perform the following statements:

Console.WriteLine("PageAppearance property values:");
Console.WriteLine("RemoteOnly = " + pageAppearanceConfig.RemoteOnly);
Console.WriteLine("Font: Name = {0}, Size = {1}",
    pageAppearanceConfig.Font.Name,
    pageAppearanceConfig.Font.Size);
Console.WriteLine("Color: Foreground {0}, Background {1}",
    pageAppearanceConfig.Color.Foreground,
    pageAppearanceConfig.Color.Background);

Note: To understand the App.Config I changed the namespace into MyNameSpace. The assembly name is still TryConfigManagement

For completeness the contents of App.Config. Note where the namespace and assembly name are used

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <!-- Configuration section-handler declaration area.  -->
      <configSections>
        <sectionGroup name ="pageAppearanceGroup">
          <section name="pageAppearance"
                   type ="TryConfigManagement.PageAppearanceSection, TryConfigManagement"
                   allowLocation="true"
                   allowDefinition="Everywhere"
                   />
        </sectionGroup>
      </configSections>

      <!-- Configuration section settings area. -->
      <pageAppearanceGroup>
         <pageAppearance>
          <font name="TimeNewRoman" size="18"/>
          <color background="000000" foreground="FFFFFF"/>
        </pageAppearance>  
      </pageAppearanceGroup>
    </configuration>

The fields of the section definition:

  • name of the setting in the configuration settings area. Must be in the same settings group
  • type: the actual type of ( the derived class of) the configurationSection. This includes the namespace. After the semicolon comes the assembly name. This doesn't have to be the full assemblyName

Now all I have to do if find a method to get rid of all the magic strings. But that's a different matter.