Can't Get Custom Configuration Section to Work

8.4k views Asked by At

I am trying to create a custom configuration that looks like this.

<configuration>
  <configSections>
    <section name="actions" type="ConfigurationTest.ActionsConfig, UnitTestExperiments" />
    <section name="action" type="ConfigurationTest.ActionConfig, UnitTestExperiments"/>
  </configSections>
  <actions poolSize="100">
    <action name="a1" impl="some.class1">
      <add name="key11" value="value11"/>
      <add name="key12" value="key12"/>
    </action>
    <action name="a2" impl="some.class2">
      <add name="key21" value="value21"/>
      <add name="key22" value="key22"/>
    </action>
  </actions>
</configuration>

Here the <action> tag can occur N times and every action will have a unique set of keys. I tried a couple of different solutions and options but it seems like I cannot get the class structure/mapping correct. I am hoping to get a structure that I can call like this.

    using System;
    using System.Configuration;

    namespace ConfigurationTest
    {
        public class ActionsConfig : ConfigurationSection
        {
            [ConfigurationProperty("poolSize")]
            public string PoolSize
            {
                get { return (string)this["poolSize"]; }
            }

            [ConfigurationProperty("", IsRequired = true, IsDefaultCollection = true)]
            public ActionList Instances
            {
                get { return (ActionList)this[""]; }
                set { this[""] = value; }
            }
        }

        public class ActionList : ConfigurationElementCollection
        {
            protected override ConfigurationElement CreateNewElement()
            {
                return new ActionConfig();
            }

            protected override object GetElementKey(ConfigurationElement element)
            {
                return ((ActionConfig)element).Name;
            }
        }

        public class ActionConfig : ConfigurationSection
        {
            [ConfigurationProperty("name")]
            public string Name
            {
                get { return (string)this["name"]; }
            }

            [ConfigurationProperty("impl")]
            public string Impl
            {
                get { return (string)this["impl"]; }
            }

            [ConfigurationProperty("", IsDefaultCollection = true)]
            public NameValueConfigurationCollection Settings
            {
                get
                {
                    return (NameValueConfigurationCollection)base[""];
                }
            }
        }



   public class Program
        {
            static void Main(string[] args)
            {
                ActionsConfig ac = ConfigurationManager.GetSection("actions") as ActionsConfig;
                Console.WriteLine(ac.PoolSize);
                ActionConfig nameValueSection = ac.CurrentConfiguration.GetSection("action") as ActionConfig;
                NameValueConfigurationCollection settings = nameValueSection.Settings;
                foreach (var key in settings.AllKeys)
                {
                    Console.WriteLine(settings[key].Name + ": " + settings[key].Value);
                }
            }
        }
    }

Exception trace is below.

    System.Configuration.ConfigurationErrorsException was unhandled
  Message=Unrecognized element 'action'. (UnitTestExperiments.vshost.exe.Config line 8)
  Source=System.Configuration
  BareMessage=Unrecognized element 'action'.
  Filename=UnitTestExperiments.vshost.exe.Config
  Line=8
  StackTrace:
       at System.Configuration.BaseConfigurationRecord.EvaluateOne(String[] keys, SectionInput input, Boolean isTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult)
       at System.Configuration.BaseConfigurationRecord.Evaluate(FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult, Boolean getLkg, Boolean getRuntimeObject, Object& result, Object& resultRuntimeObject)
       at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
       at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
       at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
       at System.Configuration.BaseConfigurationRecord.GetSection(String configKey)
       at System.Configuration.ConfigurationManager.GetSection(String sectionName)
       at ConfigurationTest.Program.Main(String[] args) in C:\Users\me\Documents\Visual Studio 2010\Projects\UnitTestExperiments\Program.cs:line 63
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
2

There are 2 answers

2
Erik Philips On

Take a look at use Custom Configuration Settings. This has a very good example.

Updates

Custom ADD sections take a look at the example Custom ConfigurationSections in .NET 2.0 .config Files

0
DotNet n00b On

I got the EXACT answer from the demo project Here

I had to extend the code to an extra layer to make it work for me.